Cpp*_*oob 12 c++ multithreading memory-model c++11 relaxed-atomics
请考虑以下代码片段摘自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) == 0) {
delete control_block_ptr;
}
}
Run Code Online (Sandbox Code Playgroud)
Herb Sutter说,线程A 中引用的增量可以使用memory_order_relaxed,因为"没有人根据动作做任何事情".现在我理解memory_order_relaxed,如果refs在某个时刻等于N ,则两个线程A和B执行以下代码:
control_block_ptr->refs.fetch_add(1, memory_order_relaxed);
Run Code Online (Sandbox Code Playgroud)
然后可能会发生两个线程都认为refs的值为N并且都将N + 1写回它.这显然不起作用,memory_order_acq_rel应该像析构函数一样使用.我哪里错了?
编辑1:考虑以下代码.
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);
Run Code Online (Sandbox Code Playgroud)
在调用fetch_add之前,线程2观察到的引用值是多少?可能是N还是N + 1?调用fetch_add后,线程2观察到的引用值是多少?它必须至少是N + 2吗?
[对话URL:C++&超越2012 - http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-2-of-2(@ 1: 20:00)]
模拟的Boost.Atomic库std::atomic提供类似的引用计数示例和解释,它可能有助于您理解.
增加引用计数器总是可以通过以下方式完成
memory_order_relaxed:对象的新引用只能从现有引用形成,并且将现有引用从一个线程传递到另一个线程必须已经提供任何所需的同步.在删除不同线程中的对象之前,必须在一个线程(通过现有引用)中强制执行对对象的任何可能访问.这是通过在删除引用之后的"释放"操作(通过此引用对对象的任何访问必须明显发生之前)和在删除对象之前的"获取"操作来实现的.
可以
memory_order_acq_rel用于fetch_sub操作,但是当参考计数器尚未达到零并且可能施加性能损失时,这导致不需要的"获取"操作.
| 归档时间: |
|
| 查看次数: |
3547 次 |
| 最近记录: |