2012-10-04 6 views
7

このプログラムは2つの異なるスレッドを実行し、「レース」の勝者が誰であるかを教えてくれます。デッカーのアルゴリズムの混乱の変形

時には、両方のスレッドが「勝利」している(私は誰か、誰も勝つことを期待していない)。これは期待される行動ですか、なぜですか?私は明らかにここで基本的な何かを欠いている。

class Program 
{ 
    public volatile static int a = 0; 
    public volatile static int b = 0; 

    public static void Main() 
    { 
     for(int i = 0; i < 1000; i++) 
     { 
      a = 0; 
      b = 0; 

      Parallel.Invoke(delegate { a = 1; if (b == 0) Console.WriteLine("A wins"); }, 
          delegate { b = 1; if (a == 0) Console.WriteLine("B wins"); }); 

      Console.WriteLine(System.Environment.NewLine); 

      Thread.Sleep(500); 
     } 
    } 
} 

結果:

A wins 

B wins 

A wins 
B wins 

A wins 

... 
+0

実装を 'Parallel'から貧弱な古い' Thread'sに変更すると、うまくいくように思えます。なぜか分かりません。 –

+0

@LB:興味深いのは、コア? –

+0

'TaskCreationOptions.LongRunning'も正しく動作するように設定されています。 –

答えて

3

あなたは間違って揮発使用している:

を揮発性の変数を宣言するには十分ではありません、あなたは必ずはどこでもあなたが読んで/それらを書く、あなたはまた、Thread.VolatileRead(ref myVar)/Thread.VolatileWrite(ref myVar)

、揮発性を使用することを確認する必要がありNOT正しく使用されていても、(別のスレッドからの)読み取り/書き込みの順序を保証します。 SOを参照して、トピックに関する情報を入手してください。 EDIT:x86のシングルコアマシン上のit seems to do

あなたは、単にlockステートメントを使用することができますが、あなたがこのの底に取得したい場合、私は再びthis free e-book

を読んで、理解を読んrecommand追加:
.NET 4のParallelクラスを閲覧したところ、volatileというキーワードは使用されていません。
彼らは何らかの理由でループする前にAction<T>の配列もコピーしますが、それがあなたに影響するかどうかは疑問です。

+0

+1。スレッドの使用。VolatileRead(ref myVar)などは実際に期待される動作を与えます。私が推測したことは、変数を揮発性(正しいメモリバリアを挿入しない)として宣言しないと、メモリモデルの緩和されたモデルの良い例が得られるということです。あなたがその上で自由に感じることを手がけたいなら。私はおそらくこれがなぜ起こったのかについてのより詳細な説明が与えられていなければ、これを受け入れられたものとしてマークするでしょう。ありがとう! –

+0

@ JK。 *詳しい*説明のために無料の電子書籍を読んでください(しかし、あなた自身を支えてください!)。 –

+0

私は電子ブックを読んだ。私の理解から、VolatileReadはMemoryBarrierを追加します。ただし、これは、2番目のスレッドが最初のスレッドが書き込んだ "新鮮な"値を読み取ることができるとは保証しません。だから、たとえこれが機能していても、理論的には(少なくともVolatileReadとVolatieWriteメソッドを使用してはいけない)と思う。 – Petrakeas

1

両方のWin彼らは並列に実行されます。

ドキュメント(http://msdn.microsoft.com/en-us/library/system.threading.tasks.parallel.invoke.aspx)から:の可能な場合は、のアクションが実行されます。

+0

+1良いキャッチ! – Gabber

+3

これはまだ奇妙です。 aとbは揮発性で、他のタスクの値をチェックする前に更新されます。これは、aがb == 1であるかどうかをチェックしているとき、少なくともaは1でなければならず、その逆でなければならないことを意味するので、論理的には最大で1つは勝てるように見える。 – GolezTrol

+0

@GolezTrolは理にかなっていますが、揮発性と宣言されていても使用されるわけではありません:Volatile.Read/Volatile.Writeを使わずに取得/設定します –