5

(注:私はすでにこの質問をしましたが、答えはJavaに固有のものだったので、C#と.NETフレームワークについて同じ質問をしています。重複ではありません。)

私はしばらくこのパターンを使用してきましたが、最近になって、これを行うのは問題があるのではないかと考えるようになりました。基本的に、私はこのパターンのいくつかの変形を使用します:

public class SampleAsync
{
    public SampleAsync() { }

    private bool completed;
    public void Start()
    {
        var worker = new BackgroundWorker();
        worker.DoWork += (sender, e) => {
            //... do something on a different thread
            completed = true;
        };
        worker.RunWorkerAsync();
    }

    public void Update()
    {
        if (!completed) return;
        //... do something else
    }
}

Start*ユーザーは、一度だけ呼び出されることを確認する責任があります。Updateいつでもどこでも呼び出されます。

私はこれが C#/.NET フレームワークではスレッドセーフであると常に想定してきました。厳密に同期されるものは何もないにもかかわらず、completedtrue に設定しただけだからです。であることが観察されるとtrue、 にリセットされませんfalse。コンストラクターで false に初期化されます。これは、定義上、スレッドセーフです (何か愚かなことをしない限り)。では、このようにリセット不可能なフラグを使用することはスレッドセーフですか? (もしそうなら、それはパフォーマンス上の利点さえ提供しますか?)

ありがとう

4

2 に答える 2

4

ターゲット アーキテクチャに大きく依存します。Intel プロセッサは強力なメモリ モデルを備えているため、このようなコードでうまくいく傾向があります。しかし、ジッターはあなたを台無しにするかもしれません. たとえば、x86 ジッタは、特に if() ステートメントがタイトなループに現れる場合に、変数を cpu レジスタに格納する傾向があります。そして、リリースビルドでのみそうする、すばらしいデバッグの悪夢. 変数volatileを宣言することは、そのためのバンドエイドです。x64 ジッターは、少なくとも現在のバージョンでは必要ありません。しかし、ARM や Itanium などのメモリ モデルが弱いプロセッサでは、応急処置を行っても出血を止められない傾向があります。彼らは確かに、変数の更新された状態が別のスレッドですぐに見えるとは約束していません。スレッド スケジューラは、CPU キャッシュをフラッシュする傾向があります。最終的。

これを正しく行わないと意味がありません。AutoResetEvent などの適切な同期オブジェクトを使用します。または、サイクルが気になる場合は Interlocked.CompareExchange() 。

于 2013-05-09T14:10:01.940 に答える