静止整合性が構成的であるが、順次整合性が構成されていない理由


7

これら2つのメモリ整合性モデルの比較に問題があります。

基本的には、シーケンシャルな一貫性のために、次のような実際のコードを考えます。

int x, y;

void ThreadA()
{
   x = 20; //Write
   int a = y; //Read
}

void ThreadB()
{
    y = 20;
    int b = x;
}

シーケンシャル一貫性の環境ではそれは不可能だためaか、bのどちらかである20ではないとa = 20b = 20a = 20 && b = 20

しかし、静止時の一貫性はこの例にどのように適合し、なぜ構成的であるのでしょうか。

回答:


10

返信が遅くなって申し訳ありませんが、質問(確かに質問)を見つけました。私は並行性についても勉強しています。いくつかのアイデアを皆さんと共有するように努めます。

まず、シーケンシャルな一貫性から始めましょう。操作がプログラムの順序で有効に見える場合、モデルにはこのプロパティがあります。つまり、コードの行が実行される順序は、ソースファイルで指定された順序です。この前提条件はスレッド固有です。異なるスレッドを含む操作は、プログラムの順序とは無関係です。したがって、このプロパティは次のことを許可します。同じスレッドによって発行された操作は、スレッドのソースコードで指定された同じ順序で実行されます。異なるスレッドによって発行された操作は、任意の順序で発生する可能性があります。この前提条件は明白に思えるかもしれませんが、常にそうであるとは限りません(コンパイラーの最適化により、操作が発行される順序が変更され、プログラムの順序がソースと異なる場合があります)。

あなたの例は正しいですが、他の例を挙げましょう。このプログラムP1について考えてみましょう(簡単に参照できるように各行にタグを付けます)。

   int x = 1;

   void ThreadA()
   {
A1:    x = x * 2;
A3:    int a = x;
   }

   void ThreadB()
   {
B2:    x = 20;
   }

最後にa = 40の順次実行はありますか?はい:B2、A1、A3。

B2とA1は任意の順序で実行できます(これらは異なるスレッドに属しています)。A1はA3の前に実行されます(プログラムの順序=ソースコードの順序)。

次に、このプログラムP2について考えます。

   int y = 1;

   void ThreadA()
   {
A2:    y = 40;
   }

   void ThreadB()
   {
B1:    y = y / 2;
B3:    int b = y;
   }

最後にb = 20の順次実行はありますか?はい:A2、B1、B3。

作曲はどうですか?P1とP2を構成しましょう。P1∘P2が得られます。

   int x = 1;
   int y = 1;

   void ThreadA()
   {
A1:    x = x * 2;
A2:    y = 40;
A3:    int a = x;
   }

   void ThreadB()
   {
B1:    y = y / 2;
B2:    x = 20;
B3:    int b = y;
   }

逐次一貫性が構成的である場合、最後にa = 40およびb = 20の実行が必要です。これは本当ですか?いいえ。それが事実ではない理由を正式に証明しましょう。「o1→o2」と書いて、操作o2の前に操作o1を実行する必要があることを示します。

P1∘P2では、逐次一貫性により、A1-> A2およびB1-> B2(スレッドプログラムごとの順序)が成り立つ必要があります。a = 40を得るには、B2-> A1も保持する必要があります。b = 20を取得するには、A2-> B1も保持する必要があります。優先チェーンを確認できますか?A1-> A2-> B1-> B2-> A1-> ...

P1とP2は連続して一貫していたが、それらの構成P1∘P2は一致していませんでした。逐次一貫性は構成的ではありません。あなたが提供した例は、この事実を示すほどトリッキーではありませんでした。

それでは、静止一貫性について考えてみましょう。オブジェクト指向のパラダイムを使わずにこの特性を説明するのは難しいです。実際、静止時の一貫性は、オブジェクトに対する保留中のメソッド呼び出しに関して簡単に理解できます。それにもかかわらず、私は命令パラダイムに固執しようとします(保留中のメソッド呼び出しは関数が開始されますが、完了されず、オブジェクトは関数に含まれる変数になります)。

関数呼び出しは、呼び出しと応答で構成されます。スレッドによって呼び出された関数は保留中ですが、そのようなスレッドにまだ応答を返していません。変数の休止期間は、(スレッドによる)保留中の関数呼び出しが動作していない時間間隔です。同じ変数で動作し、休止期間で区切られた関数呼び出しがリアルタイムの順序(ソースコードで指定された順序)で有効に見える場合、モデルには休止整合性プロパティがあります。逆の観点から見ると、定義は、異なるスレッドによって同時に呼び出された関数によって実行された同じ変数に対する操作(静止によって分離されていない)は任意の順序で発生する可能性があると述べています。

私は何時間にもわたって、読み書き操作のみを使用して意味のある例を設計し、静止と順次の一貫性の違いを示してきましたが、成功しませんでした。セットを含む別の例を使用してみましょう。ビットベクトルを使用して、セットに含まれる整数(0〜4)を追跡します。

   int set[5] = {0, 0, 0, 0, 0};  // 0 if i-th item is absent, 1 otherwise

   void add(int number) {
L1:    set[number] = 1;
L2:    temp foo = set[0];
   }

   void remove(int number) {
       set[number] = 0;
   }

   int contains(int number) {
       return set[number] == 1;
   }

   void ThreadA()
   {
A1:    add(1);
   }

   void ThreadB()
   {
B1:    add(2);
B2:    remove(2);
B3:    int res = contains(2);
   }

最後にres = 1となる順次実行はありますか?いいえ:B1-> B2およびB2-> B3の順次整合性により、B1-> B3となります。したがって、remove(2)は常にadd(2)の後に実行され、contains(2)は常に0を返します。

最後に、res = 1の静止実行はありますか?はい!この実行を検討してください:

スレッドAはA1でadd(1)を呼び出します。

スレッドAはL1を実行します(L2は実行しません)。//セットに保留中の呼び出しがあるため、これらの呼び出しにもセットが含まれるため、スレッドBはB1の前にB2を自由に実行できます。

スレッドBはB2を呼び出します。//呼び出し+応答

スレッドBがB1を呼び出します。//呼び出し+応答

スレッドAがL2を実行し、add(1)が応答します。//セットに静止があります

スレッドBはB3を実行します。//呼び出し+応答

現在、res = 1です。

残念ながら、静止整合性が構成的である理由に関する最新の質問にはまだ答えられません。この正確な答えを確かに探していたときに、あなたの質問を見つけました。何か思いついたらお知らせします。

このトピックに関する良い読み物は、HerlihyとShavitによる本「マルチプロセッサプログラミングの芸術」の3.3章を参照してください。

編集:静止整合性が構成的である理由を説明する素晴らしいページを見つけました。そして、これは別の非常に良い読書です!

EDIT2:逐次一貫性構成可能性の例の小さなエラーを修正しました。


難しい質問への素晴らしい答えは乾杯!(私はそれが何ヶ月も誰も答えなかったことに触れたと思った:P)。
William

静止一貫性とシーケンシャル一貫性を個別に(厳密な一貫性と同様に)頭に入れることができますが、それらを相互に関連付けると非常に難しいことに気づきます。最初の例では、実行がリアルタイムでB2、A1、A3だった場合、厳密な一貫性の下では、a = 40以外は不可能です。
William

しかし、私は5分の1の一貫性が「構成的」であることの真の意味が理解できないと思います。私はあなたの3番目の例を30回(そしてもちろん説明)読みましたが、理解するのに苦労しています!
William

まず、P1∘P2の例の説明の小さなエラーを修正しました。しかし、なぜシーケンシャルコンシステンシー(SC)が構成的でないのかはすでに明らかでした。第二に、A1、A3、B2が合法であり、a = 20になるため、最初の例では、SCモデルを想定した唯一の結果はa = 40だけではありません。最後の例の目標は、SC間の違いを強調することでした。静止整合性(QC)(res = 1は1つのモデルでは可能であり、もう1つのモデルでは不可能です)。QC構成可能性のトピックについては説明しませんでした。最初の編集で提供されたリンクを読んで、テーマに関する洞察を得てください
Shadow Template

@William、なぜadd(2)とremove(2)の間でオブジェクトに静止期間を強制しないようにしたのか(スレッドAがオブジェクトに対して保留中のメソッド呼び出しを持っていると仮定して)わかりませんでした。または、スレッドAにadd()メソッドの実行を完了させ、次にスレッドBがB2を実行し、次にB1を実行した場合、それは問題になります。このシーケンスは静止的に一貫していますか?
Saurabh Raje
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.