我试图查找有关此内容的详细信息,甚至阅读了有关互斥锁和原子的标准...但仍然无法理解C++11内存模型可见性保证。 据我所知,互斥锁除了实现互斥访问之外,最重要的功能是确保可见性。即每次只有一个线程增加计数器是不够的,重要的是该线程增加由上一个使用互斥锁的线程存储的计数器(当讨论互斥锁时,人们为什么不经常提到这一点,我真的不知道为什么,也许是因为我的老师不好:))。 所以我可以告诉原子操作并不强制立即可见性: (来自维护boost::thread并实现了c++11线程和互斥库的人):
使用memory_order_seq_cst的栅栏不强制立即对其他线程可见(MFENCE指令也不会)。 C++0x内存排序约束只是这样-排序约束。memory_order_seq_cst操作形成一个总序,但是对于该序没有任何限制,除了所有线程都必须同意它,而且不能违反其他排序约束。特别地,线程可能会继续一段时间看到“旧”的值,前提是看到的值与约束一致的顺序。
我可以接受这一点。但问题是我很难理解有关原子的C++11构造物中哪些是“全局的”,哪些仅确保原子变量的一致性。 特别地,我不明白以下任何一个(如果有)内存序列确保在加载和存储之前和之后都有内存栅栏: http://www.stdthread.co.uk/doc/headers/atomic/memory_order.html
据我所知,std::memory_order_seq_cst会插入内存障碍,而其他方式仅强制执行对某些内存位置上操作的排序。
因此,有人能否澄清这一点,我想许多人将使用std::atomic制造可怕的错误,尤其是如果他们不使用默认的(std::memory_order_seq_cst内存排序)。
2. 如果我是正确的,那么这段代码中的第二行是否是多余的:
atomicVar.store(42);
std::atomic_thread_fence(std::memory_order_seq_cst);
3. std::atomic_thread_fence是否与mutex有类似的要求,以确保在非原子变量上实现seq一致性,需要在加载之前执行std::atomic_thread_fence(std::memory_order_seq_cst), 并且在存储之后执行std::atomic_thread_fence(std::memory_order_seq_cst)?
4. 是否
{
regularSum+=atomicVar.load();
regularVar1++;
regularVar2++;
}
//...
{
regularVar1++;
regularVar2++;
atomicVar.store(74656);
}
等同于
std::mutex mtx;
{
std::unique_lock<std::mutex> ul(mtx);
sum+=nowRegularVar;
regularVar++;
regularVar2++;
}
//..
{
std::unique_lock<std::mutex> ul(mtx);
regularVar1++;
regularVar2++;
nowRegularVar=(74656);
}
我认为不会,但我想确认一下。编辑: 5. 断言能触发吗? 只有两个线程存在。
atomic<int*> p=nullptr;
第一个线程写入
{
nonatomic_p=(int*) malloc(16*1024*sizeof(int));
for(int i=0;i<16*1024;++i)
nonatomic_p[i]=42;
p=nonatomic;
}
第二个线程读取
{
while (p==nullptr)
{
}
assert(p[1234]==42);//1234-random idx in array
}
nonatomic_p[i]
的赋值不能在p
的赋值之后移动。 - Anthony WilliamsregularVar1
和regularVar2
的写入。如果有任何其他线程从regularVar1
和regularVar2
读取而没有进行同步,那么也会出现数据竞争。 - Anthony Williamsa.load(mo_acquire)
比a.load(mo_relaxed); fence(mo_acquire)
更弱。Preshing解释(http://preshing.com/20131125/acquire-and-release-fences-dont-work-the-way-youd-expect/)fence是双向屏障,但acquire-load只是单向屏障:早期的loads可以重新排序到`a.load(mo_acquire)`一直到临界区域或任何其他地方。但是load-fence会阻止*所有*加载在其两侧重新排序。因此,您的前几句话并不完全准确。 - Peter Cordes