13

ワーカー スレッドにオブジェクトがあり、実行を停止するように指示できます。bool または AutoResetEvent を使用してこれを実装できます。

ブール値:

private volatile bool _isRunning;

public void Run() {
    while (_isRunning)
    {
        doWork();
        Thread.Sleep(1000);
    }
}

自動リセットイベント:

private AutoResetEvent _stop;

public void Run() {
    do {
        doWork();
    } while (!_stop.WaitOne(1000));
}

Stop()メソッドは false に設定される_isRunningか、 を呼び出します_stop.Set()

それとは別に、AutoResetEvent を使用したソリューションは少し速く停止する可能性がありますが、これらの方法に違いはありますか? 一方が他方よりも「優れている」か?

4

5 に答える 5

12

C# volatileは、すべての保証を提供するわけではありません。古いデータを読み取る可能性があります。はるかに強力な保証を提供するため、基盤となる OS 同期メカニズムを使用することをお勧めします。

これはすべて、Eric Lippert によって非常に詳細に議論されています (本当に読む価値があります)。ここに短い引用があります。

C# では、「揮発性」は、「コンパイラーとジッターがコードの並べ替えを実行したり、この変数でキャッシュの最適化を登録したりしないことを確認する」ことを意味するだけではありませんまた、「他のプロセッサを停止し、メインメモリとキャッシュを同期させることを意味する場合でも、最新の値を読み取っていることを確認するために必要なことは何でも行うようにプロセッサに指示する」ことも意味します。

実際、最後のビットは嘘です。揮発性の読み取りと書き込みの真のセマンティクスは、ここで概説したよりもかなり複雑です。実際、すべてのプロセッサが実行中の処理を停止し、メイン メモリとの間でキャッシュを更新することを実際に保証するわけではありません。むしろ、それらは、読み取りと書き込みの前後のメモリアクセスが相互にどのように順序付けられていることが観察されるかについて、より弱い保証を提供します。 新しいスレッドの作成、ロックの開始、Interlocked ファミリーのメソッドの使用などの特定の操作では、順序付けの監視に関してより強力な保証が導入されます。詳細については、C# 4.0 仕様のセクション 3.10 および 10.5.3 を参照してください。

率直に言って、不安定なフィールドを作成しないようお勧めします。揮発性フィールドは、まったくおかしなことをしている兆候です。ロックを設定せずに、2 つの異なるスレッドで同じ値を読み書きしようとしています。ロックは、ロック内で読み取りまたは変更されたメモリが一貫していることを保証し、ロックは一度に 1 つのスレッドのみが特定のメモリの塊にアクセスすることを保証します。

于 2012-08-14T13:45:21.437 に答える
7

揮発性は十分ではありませんが、オペレーティング システムのスケジューラは最終的に常にロックを取得するため、実際には常に機能します。また、コア間でキャッシュの同期を維持するために大量のジュースを消費する x86 など、強力なメモリ モデルを備えたコアでもうまく機能します。

したがって、本当に重要なのは、スレッドが停止要求にどれだけ迅速に応答するかだけです。測定は簡単です。コントロール スレッドでストップウォッチを開始し、ワーカー スレッドで while ループの後の時間を記録するだけです。1000回のサンプルの取得と平均の取得を10回繰り返して測定した結果は次のとおりです。

volatile bool, x86:         550 nanoseconds
volatile bool, x64:         550 nanoseconds
ManualResetEvent, x86:     2270 nanoseconds
ManualResetEvent, x64:     2250 nanoseconds
AutoResetEvent, x86:       2500 nanoseconds
AutoResetEvent, x64:       2100 nanoseconds
ManualResetEventSlim, x86:  650 nanoseconds
ManualResetEventSlim, x64:  630 nanoseconds

ARM や Itanium などの弱いメモリ モデルのプロセッサでは、volatile bool の結果がそれほどうまく表示されない可能性が非常に高いことに注意してください。テストするものはありません。

明らかに、ManualResetEventSlim を優先して、優れたパフォーマンスと保証を提供したいと考えているようです。

これらの結果の 1 つの注意点は、ワーカー スレッドがホット ループを実行し、停止条件を常にテストし、他の作業を行わない状態で測定されたことです。これは実際のコードと完全に一致するわけではありません。通常、スレッドは停止条件をそれほど頻繁にチェックしません。そのため、これらの手法の違いはほとんど重要ではありません。

于 2012-08-15T01:17:03.547 に答える
3

この場合、重要なキーワードをAutoResetEvent忘れることができないため、IMHOの方が優れています。volatile

于 2012-08-14T13:25:38.160 に答える
1

volatileキーワードを使用する前に、これを読む必要があります。マルチスレッドを調査するときは、 http://www.albahari.com/threading/の記事全体を読むことができると思います。

キーワードの微妙な点volatileと、その動作が予期しないものになる理由について説明します。


volatileを使用すると、読み取りと書き込みが並べ替えられる可能性があり、密接に並行する状況で余分な反復が発生する可能性があることに注意してください。この場合、さらに1秒ほど待たなければならない場合があります。


調べてみると、いくつかの理由であなたのコードは機能しないと思います。

「boolean:」スニペットは常に約1秒間スリープしますが、おそらく必要なものではありません。

「AutoResetEvent:」スニペットはインスタンス化さ_stopれず、常にdoWork()少なくとも1回は実行されます。

于 2012-08-14T13:36:26.047 に答える
0

上記のスニペットがすべてであるかどうかによって異なります。AutoReset イベントは、その名前が示すように、WaitOne が渡された後にリセットされます。これは、bool を使用するのではなく、すぐに再び使用できることを意味し、true に戻す必要があります。

于 2012-08-14T13:29:16.023 に答える