考虑以下摘自 Herb Sutter 关于原子的演讲的代码片段:
smart_ptr 类包含一个名为 control_block_ptr 的 pimpl 对象,其中包含引用计数refs.
// 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;
}
}
赫伯·萨特说增量refs线程 A 中可以使用 memory_order_relaxed 因为“没有人根据该操作执行任何操作”。现在据我了解 memory_order_relaxed,如果refs在某个时刻等于 N,两个线程 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);
有什么价值refs在调用 fetch_add 之前线程 2 观察到了什么?可以是N或N+1吗?调用 fetch_add 后,线程 2 观察到的 refs 值是多少?必须至少是N+2吗?
[演讲网址:C++ & Beyond 2012 -http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-2-of-2 http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-2-of-2(@ 1:20:00)]