8

私はメモリバリアの理解を深めようとしています。弱いメモリモデルがあり、デッカーのアルゴリズムを適応させたとします。メモリバリアを追加することで、弱いメモリモデルで正しく動作させることは可能ですか?

答えは意外とノーだと思います。その理由は(私が正しければ)、メモリバリアを使用して読み取りが別の読み取りを超えないようにすることはできますが、読み取りが古いデータ(キャッシュ内のデータなど)を認識しないようにすることはできないためです。したがって、クリティカルセクションが(CPUのキャッシュごとに)ロック解除された過去のある時点を確認できましたが、現時点では、他のプロセッサがそれをロックされていると見なす可能性があります。私の理解が正しければ、複数のプロセッサ間でメモリ位置の値が同期して一致するように、一般にテストアンドセットまたはコンペアアンドスワップと呼ばれる操作を使用する必要があります。

したがって、弱いメモリモデルシステムがメモリバリアのみを提供することはないと正しく期待できますか?システムが有用であるためには、テストアンドセットやコンペアアンドスワップなどの操作を提供する必要があります。

x86を含む一般的なプロセッサは、弱いメモリモデルよりもはるかに強力なメモリモデルを提供していることを認識しています。弱いメモリモデルに焦点を当てて議論してください。

(デッカーのアルゴリズムが適切でない場合は、可能であれば、メモリバリアが正しい同期を正常に達成できる別の相互排除アルゴリズムを選択してください。)

4

3 に答える 3

5

確かに、メモリバリアでは、読み取りで最新の値が表示されることを保証できません。それが行うことは、単一のスレッド上とスレッド間の両方で、操作間で順序付けを強制することです。

たとえば、スレッドAが一連のストアを実行してから、フラグの場所への最終ストアの前にリリースバリアを実行し、スレッドBがフラグの場所から読み取り、他の値を読み取る前に取得バリアを実行すると、他の変数はスレッドAによって値が保存されている:

// initially x=y=z=flag=0

// thread A
x=1;
y=2;
z=3;
release_barrier();
flag=1;

// thread B
while(flag==0) ; // loop until flag is 1
acquire_barrier();
assert(x==1);  // asserts will not fire
assert(y==2);
assert(z==3);

もちろん、ロードとストア先flagがアトミックであることを確認する必要があります(変数が適切に配置されている場合、単純なロードとストアの命令は最も一般的なCPUにあります)。スレッドBでwhileループがないと、スレッドBはの古い値(0)を読み取る可能性がありflag、したがって、他の変数で読み取られる値を保証することはできません。

したがって、フェンスを使用して、デッカーのアルゴリズムで同期を強制することができます。

C ++での実装例を次に示します(C ++ 0xアトミック変数を使用)。

std::atomic<bool> flag0(false),flag1(false);
std::atomic<int> turn(0);

void p0()
{
    flag0.store(true,std::memory_order_relaxed);
    std::atomic_thread_fence(std::memory_order_seq_cst);

    while (flag1.load(std::memory_order_relaxed))
    {
        if (turn.load(std::memory_order_relaxed) != 0)
        {
            flag0.store(false,std::memory_order_relaxed);
            while (turn.load(std::memory_order_relaxed) != 0)
            {
            }
            flag0.store(true,std::memory_order_relaxed);
            std::atomic_thread_fence(std::memory_order_seq_cst);
        }
    }
    std::atomic_thread_fence(std::memory_order_acquire);

    // critical section


    turn.store(1,std::memory_order_relaxed);
    std::atomic_thread_fence(std::memory_order_release);
    flag0.store(false,std::memory_order_relaxed);
}

void p1()
{
    flag1.store(true,std::memory_order_relaxed);
    std::atomic_thread_fence(std::memory_order_seq_cst);

    while (flag0.load(std::memory_order_relaxed))
    {
        if (turn.load(std::memory_order_relaxed) != 1)
        {
            flag1.store(false,std::memory_order_relaxed);
            while (turn.load(std::memory_order_relaxed) != 1)
            {
            }
            flag1.store(true,std::memory_order_relaxed);
            std::atomic_thread_fence(std::memory_order_seq_cst);
        }
    }
    std::atomic_thread_fence(std::memory_order_acquire);

    // critical section


    turn.store(0,std::memory_order_relaxed);
    std::atomic_thread_fence(std::memory_order_release);
    flag1.store(false,std::memory_order_relaxed);
}

完全な分析については、http://www.justsoftwaresolutions.co.uk/threading/implementing_dekkers_algorithm_with_fences.htmlにある私のブログエントリを参照してください。

于 2010-07-26T21:24:55.603 に答える
1

すべてのステートメントの後にロードとストアのバリアを設定し、さらにコンパイラがストアを並べ替えないようにしたとします。これは、合理的なアーキテクチャでは、厳密な一貫性を提供しませんか?デッカーのアルゴリズムは、逐次一貫性のあるアーキテクチャに取り組んでいます。逐次一貫性は、厳密な一貫性よりも弱い条件です。

http://www.cs.nmsu.edu/~pfeiffer/classes/573/notes/consistency.html

整合性モデルが弱いCPUでも、キャッシュコヒーレンスが期待できます。物事が脱線するのは、ストアバッファと推測された読み取りの動作であり、使用可能な操作は、保存された書き込みをフラッシュし、推測された読み取りを無効にすることだと思います。推測された読み取りを無効にすることができるロードフェンスがない場合、またはストアバッファーをフラッシュする書き込みフェンスがない場合、デッカーを実装できないことに加えて、ミューテックスを実装することはできません。

これが私の主張です。書き込みバリアと読み取りバリアがあり、キャッシュがCPU間でコヒーレントである場合は、すべての命令の後に書き込みをフラッシュ(ストアフェンス)し、すべての命令の前に推測をフラッシュ(読み取りフェンス)することで、すべてのコードを逐次一貫性のあるものにすることができます。命令。したがって、私は、あなたが話していることにアトミックは必要なく、デッカーのアルゴリズムだけで必要なことを実行できると主張します。確かにあなたはしたくないでしょう。

ところで、私が働いている会社であるCorensicは、並行性の問題をデバッグするための優れたツールを作成しています。http://www.corensic.comをチェックしてください。

于 2010-07-24T20:00:55.227 に答える
0

一部のバリア(powerpc isync、ia64の.acqロードなど)も、後続のロードに影響を与えます。つまり、プリフェッチのためにisyncの前にロードが利用可能であった場合、それを破棄する必要があります。適切に使用すれば、おそらくそれでデッカーのアルゴリズムが弱いメモリモデルで機能するのに十分です。

また、キャッシュ無効化ロジックが機能しています。isyncなどが原因で負荷が現在のものであり、別のCPUがそれに触れると、キャッシュされたバージョンのデータが無効になることがわかっている場合は、それで十分ですか?

興味深い質問はさておき、デッカーのアルゴリズムはすべての実用的な目的のためにばかげています。実際のアプリケーションでは、アトミックハードウェアインターフェイスとメモリバリアを使用する必要があるため、デッカーのアルゴリズムをアトミックで修正する方法に焦点を当てるのは、私には価値がないようです;)

于 2010-07-23T17:07:09.370 に答える