私はAnthony WilliamsのC++ Concurrency in Actionを読んでおり、lock_free_stack
クラスのプッシュ実装について理解していません。C++ 11のロックフリースタックpush()関数の混乱
void push(T const& data)
{
counted_node_ptr new_node;
new_node.ptr=new node(data);
new_node.external_count=1;
new_node.ptr->next=head.load(std::memory_order_relaxed)
while(!head.compare_exchange_weak(new_node.ptr->next,new_node, std::memory_order_release, std::memory_order_relaxed));
}
正確には7.12をリストだから、2つのスレッド(A
、B
)はプッシュ機能を呼び出す想像してみてください。どちらもループ中に到達しますが、起動しません。だから両方とも同じ値をhead.load(std::memory_order_relaxed)
から読んだ。
その後、我々が起こって、次のものを持っている:
B
スレッドがA
スレッドがループを開始し、明らかに成功したスタックに新しいノードを追加何らかの理由のためにスワイプます。B
スレッドはトラックに戻り、ループも開始します。
これは私にとっては興味深いところです。 成功した場合には、std::memory_order_relaxed
とcompare_exchange_weak(..., std::memory_order_release, ...)
での負荷の操作があったため、スレッド間の同期が全くないように見えます。 std::memory_order_relaxed - std::memory_order_release
で、ではないことを意味します。std::memory_order_acquire - std::memory_order_release
です。
したがってB
スレッドは単に新しいノードをスタックに追加しますが、スタックにノードがなく、この新しいノードにヘッドをリセットしたときの初期状態になります。
私はすべてこのテーマを中心に私の研究をしていたと私は見つけることができる最高のは、この記事でDoes exchange or compare_and_exchange reads last value in modification order?
そこで質問がありました、それは本当ですか?すべてのRMW関数が最後の値を変更順に参照していますか?どんなにstd::memory_order
を使用しても、RMW操作を使用すると、すべてのスレッド(CPUなど)と同期し、アトミック操作に書き込まれる最後の値を呼び出します。