c++ - GNU C 内联汇编中的输入操作数 `"m"(var )` and Output Operand ` "=m"(var)` ?不使用任何指令作为屏障?

标签 c++ assembly x86-64 inline-assembly lock-free

我想知道 asm 中的输入操作数 "m"(var) 和输出操作数 "=m"(var) 的作用:

asm volatile("" : "=m"(blk) : :);
asm volatile("" : : "m"(write_idx), "m"(blk) :);

我遇到了上面的两行 here ,在 SPMC 队列中。

副作用是什么?上面的行没有 asm 指令,因此我相信作者试图利用一些明确定义的副作用(例如,如果满足以下条件,则刷新寄存器保存的 write_idxblk 的值:他们在第二行?)

最佳答案

asm volatile("" : "=m"(blk) : :);

在这条语句之后,编译器认为一些随机汇编代码已写入blk。当给出输出操作数时,编译器假定 blk 的先前值无关紧要,并且可以丢弃为 blk 赋值的代码,而在此语句之前没有人读取过该值。它还必须假设 blk 现在保存一些其他值并从内存中读回该值,而不是例如来自寄存器中的拷贝。

很快,这看起来像是试图强制编译器将blk视为是从编译器未知的源分配的。这通常可以通过将 blk 限定为 volatile 来更好地实现。

请注意,由于 asm 语句被限定为 volatile,因此该语句还意味着对编译器的排序要求,以防止某些代码重新排列。

类似的代码(尽管没有 volatile )也可用于告诉编译器您希望对象采用未指定的值作为优化。不过我建议不要使用这种伎俩。

asm volatile("" : : "m"(write_idx), "m"(blk) :);

编译器假定此语句从变量 write_idxblk 读取。因此,它必须先将这些变量的当前内容具体化到内存中,然后才能执行该语句。这看起来像是内存屏障的粗略近似,但实际上并没有像预期的那样影响内存屏障。


除此之外,您所显示的代码肯定是有缺陷的:除非另有说明,否则 C++ 对象可能不会在没有同步的情况下同时修改。但是,此代码无法进行此类同步,因为它不包含任何用于同步的类型(例如 std::atomic )或设施(例如互斥体)的 header 。

在没有详细阅读代码的情况下,我认为作者只是使用普通对象进行同步,认为并发突变是明确定义的。观察到事实并非如此,作者可能认为应该归咎于编译器,并添加这些 asm 语句作为拼凑,使其生成似乎可以工作的代码。然而,这是不正确的,尽管它似乎可以在具有足够严格的内存模型(例如 x86)和足够愚蠢的编译器的体系结构上工作,或者纯粹是运气。

不要这样编程。请改用原子或高级同步设施。

关于c++ - GNU C 内联汇编中的输入操作数 `"m"(var )` and Output Operand ` "=m"(var)` ?不使用任何指令作为屏障?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75134518/

相关文章:

c++ - websocketpp asio 监听错误

C++ 复制构造函数语法

c - 在thumb模式下编译时的GCC arm指令模式

c - 在 uint128_t 整数上下文中对十六进制字符串的操作

c++ - 使用 Visual Studio 2008 从 x86 编译 x64 dll

c++ - 找到一个矩形与另一个矩形接触的边

c++ - 谁能帮我从一个简单的 Hello World 中解释这个 MSVC Debug模式反汇编?

assembly - 将寄存器与其自身进行异或的目的是什么?

c - 单个 sqrt() 的运行速度如何比放入 for 循环时慢两倍

assembly - 在 x86 汇编中将单个内存单元设置为零或常量的最快方法?