gpt4 book ai didi

c++ - 在c++中,我们能否通过volatile +内存栅栏(sfence + lfence)保证两个线程之间发生事前?

转载 作者:行者123 更新时间:2023-12-02 10:04:58 24 4
gpt4 key购买 nike

简而言之,是否可以使用以下代码将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);

最佳答案

https://gcc.gnu.org/wiki/DontUseInlineAsm

请勿在实践中使用此代码,将std::atomic<bool>memory_order_releaseacquire结合使用可获得相同的asm代码源(但无需不必要的防护和防护)

但是,对定义volatile行为的编译器来说,看起来是安全的,这样volatile bool flag上的数据争用UB就不成问题。对于可以编译Linux内核的GCC之类的编译器,就是这种情况(像您正在执行的那样,它使用volatile滚动其自己的原子)。

ISO C++并不严格要求这样做,例如,在没有一致性共享内存的计算机上可能存在一种假设的实现,因此原子存储将需要显式刷新。但是实际上没有任何这样的实现。 (不过,有些嵌入式系统中volatile存储使用不同或额外的指令来使MMIO正常工作。)

存储之前的障碍使其成为发布存储,而加载之后的障碍使其成为获取负载。 https://preshing.com/20120913/acquire-and-release-semantics/发生之前,只能通过获取负载看到的发布存储建立。

x86 asm内存模型已经禁止除StoreLoad之外的所有重新排序,因此仅编译时重新排序需要为块。除了那些效率低下的LFENCE和SFENCE指令外,这将编译为asm,与将std::atomic<bool>mo_releasemo_acquire一起使用时得到的asm相同。

C++ How is release-and-acquire achieved on x86 only using MOV?解释了为什么x86 asm内存模型至少与acq_rel一样强。

asm语句中的sfencelfence指令与完全无关,只需要asm("" ::: "memory")编译器障碍部分。 https://preshing.com/20120625/memory-ordering-at-compile-time/。编译时重新排序仅需遵守C++内存模型,但是x86内存模型将确定编译器选择的内容。 (程序顺序+具有存储转发功能的存储缓冲区=比acq_rel稍强)

(没有输出操作数的GNU C asm语句是隐式易失的,因此我省略了显式的volatile。)

(除非您试图同步NT存储库?否则,您只需要sfence,而不需要lfence。)
Does the Intel Memory Model make SFENCE and LFENCE redundant?是的。内部使用NT存储的内存集将使用sfence本身,以使其与x86上使用的standard C++ atomics / ordering -> asm mapping兼容。如果您使用其他映射(例如自由使用没有存储的NT存储),则理论上可以中断互斥锁关键部分,除非您也滚动自己的互斥锁。 (实际上,大多数互斥量实现在take和release中都使用lock ed指令,这是一个完整的障碍。)

由于x86的内存模型,带有内存缓冲区的空asm语句有点像atomic_thread_fence(std::memory_order_acquire_release)atomic_thread_fence(acq_rel)将编译为零个asm指令,仅阻止编译时重新排序。

只有seq_cst线程隔离栅需要发出任何asm指令来刷新存储缓冲区,并等待其发生,然后再进行后续加载。又名完全障碍(例如mfencelock ed指令,例如lock add qword ptr [rsp], 0)。

不要使用volatile和内联asm滚动自己的原子

是的,可以,我希望您只是想了解事物的工作原理。

由于使用lfence(乱序的执行障碍,对于内存排序基本上没有用),您最终制作出的效率远低于所需的效率,而不仅仅是编译器障碍。还有一个不必要的sfence

对于基本相同的问题,请参见When should I use _mm_sfence _mm_lfence and _mm_mfence,但使用内在函数而不是嵌入式asm。通常,您只需要在NT存储内部函数之后添加_mm_sfence(),就应该使用mfencestd::atomic留给编译器。

When to use volatile with multi threading?-通常从不;使用std::atomicmo_relaxed代替volatile

关于c++ - 在c++中,我们能否通过volatile +内存栅栏(sfence + lfence)保证两个线程之间发生事前?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60669710/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com