Herb Sutter のアトミックに関する講演から抜粋した次のコード スニペットを考えてみましょう。
smart_ptr クラスには、参照カウントrefsを含む control_block_ptr という pimpl オブジェクトが含まれています。
// Thread A:
// smart_ptr copy ctor
smart_ptr(const smart_ptr& other) {
...
control_block_ptr = other->control_block_ptr;
control_block_ptr->refs.fetch_add(1, memory_order_relaxed);
...
}
// Thread D:
// smart_ptr destructor
~smart_ptr() {
if (control_block_ptr->refs.fetch_sub(1, memory_order_acq_rel) == 1) {
delete control_block_ptr;
}
}
Herb Sutter は、「アクションに基づいて誰も何もしない」ため、スレッド A の参照のインクリメントは memory_order_relaxed を使用できると述べています。ここで、memory_order_relaxed を理解しているので、ある時点でrefsが N に等しく、2 つのスレッド A と B が次のコードを実行する場合:
control_block_ptr->refs.fetch_add(1, memory_order_relaxed);
その場合、両方のスレッドがrefsの値が N であることを認識し、両方とも N+1 をそれに書き戻すことがあります。これは明らかに機能せず、デストラクタと同じように memory_order_acq_rel を使用する必要があります。どこが間違っていますか?
EDIT1: 次のコードを検討してください。
atomic_int refs = N; // at time t0.
// [Thread 1]
refs.fetch_add(1, memory_order_relaxed); // at time t1.
// [Thread 2]
n = refs.load(memory_order_relaxed); // starting at time t2 > t1
refs.fetch_add(1, memory_order_relaxed);
n = refs.load(memory_order_relaxed);
fetch_addの呼び出し前にスレッド 2 によって観察された参照の値は何ですか? N または N+1 のどちらかでしょうか? fetch_add の呼び出し後にスレッド 2 によって観察される参照の値は何ですか? 少なくとも N+2 である必要がありますか?
【トークURL:C++ & Beyond 2012 - http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-2-of-2 (@1: 20:00)]