c - 函数调用是内存屏障吗?

标签 c

考虑这个 C 代码:

extern volatile int hardware_reg;

void f(const void *src, size_t len)
{
    void *dst = <something>;

    hardware_reg = 1;    
    memcpy(dst, src, len);    
    hardware_reg = 0;
}

memcpy() 调用必须发生在两个赋值之间。一般来说,由于编译器可能不知道被调用的函数会做什么,它无法将对函数的调用重新排序为在赋值之前或之后。然而,在这种情况下,编译器知道该函数将做什么(甚至可以插入一个内联内置替代项),并且它可以推断出 memcpy() 永远无法访问 hardware_reg。在我看来,编译器在移动 memcpy() 调用时不会遇到任何问题,如果它想这样做的话。

所以,问题是:单独的函数调用是否足以发出一个内存屏障来防止重新排序,或者,在这种情况下,在调用 memcpy()< 之前和之后是否需要显式内存屏障?

如果我误解了什么,请纠正我。

最佳答案

编译器无法重新排序 memcpy() hardware_reg = 1 之前的操作或者在 hardware_reg = 0 之后- 就是这样 volatile将确保——至少就编译器发出的指令流而言。函数调用不一定是“内存屏障”,但它是一个序列点。

C99 标准是关于 volatile 的(5.1.2.3/5 "程序执行"):

At sequence points, volatile objects are stable in the sense that previous accesses are complete and subsequent accesses have not yet occurred.

所以在 memcpy() 表示的序列点, volatile 访问 1必须发生,并且写入的 volatile 访问0不可能发生。

不过,有两点我想指出:

  1. 取决于什么<something>也就是说,如果目标缓冲区没有做任何其他事情,编译器可能能够完全删除 memcpy()手术。这就是微软提出 SecureZeroMemory() 的原因功能。 SecureZeroMemory()volatile 上运行防止优化写入的合格指针。

  2. volatile不一定意味着内存屏障(这是硬件的东西,而不仅仅是代码排序的东西),所以如果你在多进程机器或某些类型的硬件上运行,你可能需要显式调用内存屏障(在 Linux 上可能是 wmb())。

    从 MSVC 8 (VS 2005) 开始,Microsoft 记录了 volatile关键字暗示适当的内存屏障,因此可能不需要单独的特定内存屏障调用:

    Also, when optimizing, the compiler must maintain ordering among references to volatile objects as well as references to other global objects. In particular,

    • A write to a volatile object (volatile write) has Release semantics; a reference to a global or static object that occurs before a write to a volatile object in the instruction sequence will occur before that volatile write in the compiled binary.

    • A read of a volatile object (volatile read) has Acquire semantics; a reference to a global or static object that occurs after a read of volatile memory in the instruction sequence will occur after that volatile read in the compiled binary.

关于c - 函数调用是内存屏障吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5693274/

相关文章:

c - 为什么 fread() 的第一个参数被强制转换为其他类型

java - 尝试初始化 vm_args 时出错

c - 哪种数据结构在 C 中被广泛使用?

c - 使用异或在数组中重复和缺失的数字

c - 寻找有关结构指针的说明

c++ - 如何在 C 中显示输出时获取链表索引?

c - 这个具体示例是否是 C99 中 restrict 关键字的未定义行为?

c - C 中的动态结构数组

c - 在 C 中,在声明中使用 ":"运算符而不是条件运算符

java - 快速提问(尝试看看我是否明白如何做到这一点)