2013-05-09 5 views
5

(注:私はすでにこの質問をしましたが、その答えはJava固有のものでしたので、C#と.NETフレームワークについて同じ質問をしています。このパターンはしばらくありましたが、私は最近、これを行うことがOKではないかもしれないと考えるようになりました。基本的に、私はこのパターンのいくつかのバリアントを使用します。C#/ .NETでは、unresettable "flags"はスレッドセーフですか?

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はいつでもどこでも呼び出されます。

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

おかげ

+2

あなたは 'volatile'が必要です。 – SLaks

+0

C#とJavaでは?そうでなければthreadsafeですか? – aboveyou00

+1

「一度それが真実であることが確認されたら」は、「揮発性」を使用しないと起こり得ないビットです。 –

答えて

3

boolは原子タイプですので、あなたのコードは、スレッドセーフです。

MSDN:

読み込み、次のデータ・タイプの書き込みがアトミックである:BOOL、CHAR、 バイト、sbyte、短い、USHORT、UINT、整数、フロート、及び参照型。 では、元の型のの列挙型の読み書きもアトミックです。 long、ulong、double、およびdecimalを含む の型およびユーザー定義の 型の読み込みと書き込みは、アトミックであることが保証されていません。ライブラリ はその目的のために設計された機能のほかに、インクリメントまたはデクリメントの場合のように、アトミック のリード・モディファイ・ライトの保証はありません。

参照:http://msdn.microsoft.com/en-us/library/aa691278(v=vs.71).aspx

volatileを使用してフィールドをマークしてください:

private volatile bool completed; 

MSDN:

volatileキーワードは、フィールドがで プログラムで変更することができることを示していますオペレーティングシステム、ハードウェア、またはなどのもの3210は同時にスレッドを実行しています。

参照:http://msdn.microsoft.com/en-us/library/x13ttww7(v=vs.71).aspx

+0

... '[FieldOffset]'や '[StructLayout]'を使ってフィールドを明示的に揃えると、すべての賭けはオフになります。 [この質問](http://stackoverflow.com/q/15249626/146622)を参照してください。 – Virtlink

+1

これは、そのフィールドへの書き込みが他のスレッドに伝播することを保証しますか?私はそうは思わない。値は登録されている可能性があります。 – usr

+0

@usr:「他のスレッドに伝播する」とはどういう意味ですか? –

3

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

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

+0

volatileは、フィールドが直接格納され、常にメモリから再ロードされることを保証しますか? (両方のプロパティは、この作業を行うために必要です)。私はvolatileが実際に何を保証しているかは不明です。 – usr

+0

@usr:あなたは別のプロパティも必要です - それは早くまたは推測的に書かれていません。 –

+2

+1あなたの最後の段落は完全にそれを要約します。何かがスレッドセーフであるかどうか尋ねる必要はありません。同期オブジェクトと* know *を使用してください。 –

関連する問題