我一遍又一遍地阅读了关于 boost 和 std (c++11) 原子类型和操作的信息,但我仍然不确定我是否理解正确(在某些情况下我根本不理解)。所以,我有几个问题。
我用于学习的资源:
- 提升文档: http: //www.boost.org/doc/libs/1_53_0/doc/html/atomic.html
- http://www.developerfusion.com/article/138018/memory-ordering-for-atomic-operations-in-c0x/
考虑以下代码段:
atomic<bool> x,y;
void write_x_then_y()
{
x.store(true, memory_order_relaxed);
y.store(true, memory_order_release);
}
#1:是否等同于下一个?
atomic<bool> x,y;
void write_x_then_y()
{
x.store(true, memory_order_relaxed);
atomic_thread_fence(memory_order_release); // *1
y.store(true, memory_order_relaxed); // *2
}
#2:以下陈述是真的吗?
*1 行保证,当在此行下完成的操作(例如 *2)是可见的(对于使用获取的其他线程),*1 以上的代码也将是可见的(具有新值)。
Next snipped 扩展了上面的那些:
void read_y_then_x()
{
if(y.load(memory_order_acquire))
{
assert(x.load(memory_order_relaxed));
}
}
#3:是否等同于下一个?
void read_y_then_x()
{
atomic_thread_fence(memory_order_acquire); // *3
if(y.load(memory_order_relaxed)) // *4
{
assert(x.load(memory_order_relaxed)); // *5
}
}
#4:以下陈述是否正确?
- *3 行确保如果发布顺序下的某些操作(在其他线程中,如 *2)可见,则发布顺序之上的每个操作(例如 *1)也将可见。
- 这意味着 *5 处的断言永远不会失败(默认值为 false)。
- 但这并不能保证即使在物理上(在处理器中)*2 发生在 *3 之前,它也会通过上面的剪辑可见(在不同的线程中运行) - 函数 read_y_then_x() 仍然可以读取旧值。唯一可以确定的是,如果 y 为真,则 x 也为真。
#5:原子整数的递增(加 1 操作)可以是 memory_order_relaxed 并且不会丢失任何数据。唯一的问题是结果可见性的顺序和时间。
根据 boost,以下截图是工作参考计数器:
#include <boost/intrusive_ptr.hpp>
#include <boost/atomic.hpp>
class X {
public:
typedef boost::intrusive_ptr<X> pointer;
X() : refcount_(0) {}
private:
mutable boost::atomic<int> refcount_;
friend void intrusive_ptr_add_ref(const X * x)
{
x->refcount_.fetch_add(1, boost::memory_order_relaxed);
}
friend void intrusive_ptr_release(const X * x)
{
if (x->refcount_.fetch_sub(1, boost::memory_order_release) == 1) {
boost::atomic_thread_fence(boost::memory_order_acquire);
delete x;
}
}
};
#6 为什么要减少使用的 memory_order_release?它是如何工作的(在上下文中)?如果我之前写的是真的,是什么让返回的值是最新的,尤其是当我们在阅读之后而不是之前/期间使用获取时?
#7 为什么引用计数器归零后有获取命令?我们刚刚读到计数器为零并且没有使用其他原子变量(指针本身没有被标记/使用)。