简而言之,是否可以用以下代码将src
中存储的数据正确复制到dst
?
volatile bool flag = false;
// In thread A.
memset(mid, src, size);
__asm__ __volatile__("sfence" ::: "memory");
flag = true;
// In thread B.
while (flag == false);
__asm__ __volatile__("lfence" ::: "memory");
memset(dst, mid, size);
您为什么认为sfence
和lfence
完全相关?您是否要同步NT存储? (如果是这样,则只需要sfence
,而不需要lfence
。)
Does the Intel Memory Model make SFENCE and LFENCE redundant?(是)
由于您编写的代码不使用NT存储(或者如果memset在内部使用,则它本身将使用sfence
),您可以将空的asm语句与内存碎片一起使用与atomic_thread_fence(std::memory_order_acquire_release)
等效,因为x86的程序顺序+具有存储转发内存模型的存储缓冲区。
仅seq_cst线程防护需要发出任何asm指令来刷新存储缓冲区,并等待该变化在以后的任何加载之前发生。又名完全障碍(例如mfence
或lock
ed指令,例如lock add qword ptr [rsp], 0
)。
即asm("" ::: "memory")
是编译器的障碍,这就是您在x86上需要acq-rel的全部。 (没有输出操作数的GNU C asm
语句是隐式易失的。)
C++ How is release-and-acquire achieved on x86 only using MOV?
volatile
和内联asm滚动您自己的原子是的,可以,我希望您只是想了解事物的工作原理。
您最终制作出的效率比所需的要低得多,因为您使用了lfence
(乱序执行屏障,对于内存排序基本上没有用),而不仅仅是编译器屏障。还有一个不必要的sfence
。
关于基本相同的问题,请参见When should I use _mm_sfence _mm_lfence and _mm_mfence,但使用内部函数而不是嵌入式asm。通常,您只需要_mm_sfence()
在NT存储内在函数之后,并且应该将mfence
留给编译器,并带有std::atomic
。
When to use volatile with multi threading?-通常从不;将std::atomic
与mo_relaxed
而不是volatile
一起使用。
如果您询问的是C ++内存模型,那么答案是否定的,由于多种原因,您的代码不是线程安全的: