假设我们有一个具有以下实现的SyncQueue
类:
class SyncQueue {
std::mutex mtx;
std::queue<std::shared_ptr<ComplexType> > m_q;
public:
void push(const std::shared_ptr<ComplexType> & ptr) {
std::lock_guard<std::mutex> lck(mtx);
m_q.push(ptr);
}
std::shared_ptr<ComplexType> pop() {
std::lock_guard<std::mutex> lck(mtx);
std::shared_ptr<ComplexType> rv(m_q.front());
m_q.pop();
return rv;
}
};
然后我们有了使用它的代码:
SyncQueue q;
// Thread 1, Producer:
std::shared_ptr<ComplexType> ct(new ComplexType);
ct->foo = 3;
q.push(ct);
// Thread 2, Consumer:
std::shared_ptr<ComplexType> ct(q.pop());
std::cout << ct->foo << std::endl;
打印ct->foo
时,我能保证得到3
吗?mtx
为指针本身提供了先发生后发生的语义,但我不确定这是否说明了ComplexType
的内存。如果它是有保证的,这是否意味着每个互斥锁(std::lock_guard<std::mutex> lck(mtx);
)都会强制任何修改过的内存位置的完全缓存无效,直到独立内核的内存层次结构合并的地方?
std::mutex()符合mutex要求(http://en.cppreference.com/w/cpp/concept/Mutex)
之前对同一互斥对象执行的m.unlock()操作与此同步锁定操作(相当于释放获取std::memory_order)
此处解释发布获取(http://en.cppreference.com/w/cpp/atomic/memory_order)
发布获取订单
如果线程A中的原子存储被标记memory_order_release和线程B中的原子加载变量标记为memory_order_aquire,所有内存写入(非原子和松弛原子)线程A的观点在线程B中变成可见的副作用,也就是说,一旦原子加载完成,线程B就保证查看线程A写入内存的所有内容。
同步是仅在释放和获取线程之间建立原子变量。其他线程可以看到不同的内存顺序比同步线程中的一个或两个都访问。
本节中的代码示例与您的代码示例非常相似。因此,应该保证线程1中的所有写入都将在push()中的互斥解锁之前发生。
当然,如果"ct->foo=3"在实际分配发生在另一个线程中时没有任何特别棘手的含义:)
wrt缓存无效,来自cpprreference:
在强有序系统(x86、SPARC TSO、IBM大型机)上,对于大多数操作,发布-获取顺序是自动的。没有为该同步发出额外的CPU指令模式下,只有某些编译器优化会受到影响(例如编译器被禁止将非原子存储移过原子存储在原子加载之前存储释放或执行非原子加载负载获取)。在弱序系统(ARM、安腾、PowerPC)上,必须使用特殊的CPU负载或内存围栏指令。
所以这实际上取决于体系结构。