2016-12-11 11 views
2

プログラマが同期に使用する変数にvolatileキーワードを追加することを忘れた場合、キャッシュの視点(MESIプロトコル)から何が起こるかを理解したいと思います。揮発性変数を使用しない同期の壊れた場合

次のコードスニペットは、一部の繰り返しの後で単純に停止します。 2スレッドの1つ(THREAD 0を仮定しよう)がcurrentの変数をTHREAD 1によってgetNext()によって変更されていると見なしていないため、それは永遠にループしているからです。

しかし、私はなぜそれが当てはまるかわかりません。 THREAD 0はcurrentにループしており、ある時点でキャッシュラインがTHREAD1(キャッシュラインがModifiedステートに切り替えられました)によって更新され、メモリキャッシュ上に "Read"メッセージを発行してローカルキャッシュにフェッチすることがあります。変数currentvolatile修飾子を追加すると、すべて正常に動作します。

THREAD 0の実行を継続できないと思われることは何ですか。

参考:Memory Barriers: a Hardware View for Software Hackers

public class Volatile { 
    public static final int THREAD_0 = 0; 
    public static final int THREAD_1 = 1; 
    public static int current; 
    public static int counter = 0; 

    public static void main(String[] args) { 
     current = 0; 

     /** Thread 0 **/ 
     Thread thread0 = new Thread(() -> { 
      while(true) { /** THREAD_0 */ 
       while (current != THREAD_0); 

       counter++; 
       System.out.println("Thread0:" + counter); 

       current = getNext(THREAD_0); 
      } 
     }); 

     /** Thread 1 **/ 
     Thread thread1 = new Thread(() -> { 
      while(true) { /** THREAD_1 */ 
       while (current != THREAD_1); 

       counter++; 
       System.out.println("Thread1:" + counter); 

       current = getNext(THREAD_1); 
      } 
     }); 

     thread0.start(); 
     thread1.start(); 
    } 

    public static int getNext(int threadId) { 
     return threadId == THREAD_0 ? THREAD_1 : THREAD_0; 
    } 
} 

答えて

0

異なるプロセッサアーキテクチャは、キャッシュ・コヒーレンスの程度が異なることができます。スループットを最大化し、メモリを必要以上にキャッシュに同期させることが目的であるため、最小限に抑えることもできます。 Javaは、調整が必要であることを検出したときに独自のメモリ障壁を課しますが、それはプログラマがルールに従っているかどうかによって異なります。

プログラマが変数をスレッド間で共有できるように(synchronizedまたはvolatileキーワードを使用するなどの)指示を追加しない場合、JITは他のスレッドがその変数を変更していないと仮定することができ、 。その変数をテストするバイトコードは大幅に並べ替えることができます。 JITがコードを十分に並べ替えると、ハードウェアが変更を検出して新しい値をフェッチするときに問題は発生しません。練習3.1でJava並行処理から引用

:同期が存在しない場合には

は、コンパイラ、プロセッサ、およびランタイム操作は実行に表示される順にいくつかの実に奇妙なことを行うことができます。十分に同期されていないマルチスレッドプログラムでメモリアクションが発生しなければならない順序について推論しようとする試みは、ほぼ間違いです。

(いくつかの場所が不十分同期コードについての推論することは無益である場合を作るJCIP帳にあります。)

+1

あなたは完全に正しい、この問題は、JITコンパイラに関連しています。プログラムをインタプリタモード(-Xint)で起動すると、コンパイルモード(-Xcomp)では動作しませんが、永遠に動作します。この返答をありがとう! –

関連する問題