C++11 原子:将它们与内存映射 I/O 一起使用是否有意义,或者甚至可能?

C++11 atomics: does it make sense, or is it even possible, to use them with memory mapped I/O?

据我了解,C volatile 和用于内存栅栏的可选内联 asm 已用于在内存映射 I/O 之上实现设备驱动程序。 Linux 内核中可以找到几个示例。

如果我们忘记了未捕获异常的风险(如果有的话),用 C++11 原子替换它们是否有意义?或者,这可能吗?

据我了解阅读参考资料 std::atomic 旨在管理对内存的多线程访问(并发性等)。但据我所知,正如你所说,volatile 是为内存映射 I/O 和信号处理等设计的。因此,volatile 对原子访问没有影响,如果单独使用,也不能解决原子访问等多线程访问问题。反之亦然——原子不提供 volatile 的特性。

因此,您的问题的简短答案是否定的。

通常,您可以用原子替换内存栅栏,但不能 volatile,除非它与栅栏一起使用,专门用于线程间通信。

关于内存映射 I/O 原子性不够的原因是:

  • volatile 向您保证程序中对该变量的所有内存访问确实会发生,并且它们会完全按照您指定的顺序发生(在单个线程中)。
  • std::atomic 仅保证您的程序的行为 就好像 所有这些内存访问都发生了(根据 C++ 的内存模型,它不知道内存映射 I/O) 并且 - 根据指定的内存顺序 - 好像 它们以指定的顺序发生。

实际上,这意味着编译器可以,例如用单次写入替换对同一(非易失性)原子的连续写入(如果其间没有其他同步),读取也是如此。如果不使用读取的结果,它甚至可以完全消除读取(尽管编译器可能仍必须发出内存屏障)。

在更理论的层面上,如果您的编译器可以证明您的程序所做的所有操作都返回 42,则允许将其转换为一条指令,而不管您的程序在该过程中使用了多少线程和原子。如果您的程序使用 volatile 变量则不是这种情况。

编辑:例如This paper 显示了允许编译器应用于原子循环变量的一些可能的(并且可能是意外的)优化。