在c ++中,我们可以通过volatile +内存栅栏(sfence + fence)保证两个线程之间发生事前吗?

问题描述 投票:1回答:2

简而言之,是否可以用以下代码将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);
c++ x86 inline-assembly thread-synchronization memory-barriers
2个回答
1
投票

您为什么认为sfencelfence完全相关?您是否要同步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指令来刷新存储缓冲区,并等待该变化在以后的任何加载之前发生。又名完全障碍(例如mfencelock 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::atomicmo_relaxed而不是volatile一起使用。


0
投票

如果您询问的是C ++内存模型,那么答案是否定的,由于多种原因,您的代码不是线程安全的:

© www.soinside.com 2019 - 2024. All rights reserved.