我想知道 asm
中的输入操作数 "m"(var)
和输出操作数 "=m"(var)
的作用:
asm volatile("" : "=m"(blk) : :);
asm volatile("" : : "m"(write_idx), "m"(blk) :);
我遇到了上面的两行 here ,在 SPMC 队列中。
副作用是什么?上面的行没有 asm 指令,因此我相信作者试图利用一些明确定义的副作用(例如,如果满足以下条件,则刷新寄存器保存的 write_idx
和 blk
的值:他们在第二行?)
最佳答案
asm volatile("" : "=m"(blk) : :);
在这条语句之后,编译器认为一些随机汇编代码已写入blk
。当给出输出操作数时,编译器假定 blk
的先前值无关紧要,并且可以丢弃为 blk
赋值的代码,而在此语句之前没有人读取过该值。它还必须假设 blk 现在保存一些其他值并从内存中读回该值,而不是例如来自寄存器中的拷贝。
很快,这看起来像是试图强制编译器将blk
视为是从编译器未知的源分配的。这通常可以通过将 blk
限定为 volatile
来更好地实现。
请注意,由于 asm
语句被限定为 volatile
,因此该语句还意味着对编译器的排序要求,以防止某些代码重新排列。
类似的代码(尽管没有 volatile
)也可用于告诉编译器您希望对象采用未指定的值作为优化。不过我建议不要使用这种伎俩。
asm volatile("" : : "m"(write_idx), "m"(blk) :);
编译器假定此语句从变量 write_idx
和 blk
读取。因此,它必须先将这些变量的当前内容具体化到内存中,然后才能执行该语句。这看起来像是内存屏障的粗略近似,但实际上并没有像预期的那样影响内存屏障。
除此之外,您所显示的代码肯定是有缺陷的:除非另有说明,否则 C++ 对象可能不会在没有同步的情况下同时修改。但是,此代码无法进行此类同步,因为它不包含任何用于同步的类型(例如 std::atomic )或设施(例如互斥体)的 header 。
在没有详细阅读代码的情况下,我认为作者只是使用普通对象进行同步,认为并发突变是明确定义的。观察到事实并非如此,作者可能认为应该归咎于编译器,并添加这些 asm
语句作为拼凑,使其生成似乎可以工作的代码。然而,这是不正确的,尽管它似乎可以在具有足够严格的内存模型(例如 x86)和足够愚蠢的编译器的体系结构上工作,或者纯粹是运气。
不要这样编程。请改用原子或高级同步设施。
关于c++ - GNU C 内联汇编中的输入操作数 `"m"(var )` and Output Operand ` "=m"(var)` ?不使用任何指令作为屏障?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75134518/