- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
简而言之,是否可以使用以下代码将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_release
和acquire
结合使用可获得相同的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_release
和mo_acquire
一起使用时得到的asm相同。
C++ How is release-and-acquire achieved on x86 only using MOV?解释了为什么x86 asm内存模型至少与acq_rel一样强。
asm语句中的sfence
和lfence
指令与完全无关,只需要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指令来刷新存储缓冲区,并等待其发生,然后再进行后续加载。又名完全障碍(例如mfence
或lock
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()
,就应该使用mfence
将std::atomic
留给编译器。
When to use volatile with multi threading?-通常从不;使用std::atomic
和mo_relaxed
代替volatile
。
关于c++ - 在c++中,我们能否通过volatile +内存栅栏(sfence + lfence)保证两个线程之间发生事前?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60669710/
在最近的英特尔 ISA 文档中,lfence 指令已被定义为序列化指令流(防止跨指令流乱序执行)。特别是description该指令包括这一行: Specifically, LFENCE does n
我试图了解在使用 RDTSC/RDTSCP 测量时间时使用围栏的正确方法。关于与此相关的 SO 的几个问题已经得到了详尽的回答。我已经经历了其中的一些。我还浏览了这篇关于同一主题的非常有用的文章: h
正如我们从之前对 Does it make any sense instruction LFENCE in processors x86/x86_64? 的回答中了解到的那样我们不能使用 SFENCE
有谁知道为什么建议 LFENCE 指令在 Spectre #1(边界检查绕过/越界读取)的情况下停止推测执行,但在 Spectre #2(分支目标注入(inject))的情况下没用?这两个 Spect
在互联网上我经常发现 LFENCE 在 x86 处理器中没有任何意义,即它什么都不做,所以相反 MFENCE 我们可以绝对轻松地使用 SFENCE,因为 MFENCE = SFENCE + LFENC
好的,我一直在阅读 SO 关于 x86 CPU 栅栏的以下问题( LFENCE 、 SFENCE 和 MFENCE ): Does it make any sense instruction LFEN
据我所知,相对于rdtsc和rdtscp指令,处理器中的运行时排序的主要区别在于执行是否要等到所有先前的指令都在本地执行后才能执行。 换句话说,这意味着lfence + rdtsc = rdtscp,
简而言之,是否可以使用以下代码将src中存储的数据正确复制到dst中? volatile bool flag = false; // In thread A. memset(mid, src, siz
我是一名优秀的程序员,十分优秀!