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

C++ C++;11原子:将它们与内存映射I/O一起使用是否有意义,甚至可能?,c++,c++11,atomic,device-driver,memory-mapping,C++,C++11,Atomic,Device Driver,Memory Mapping,据我所知,Cvolatile和可选的内存围栏内联asm已用于在内存映射I/O上实现设备驱动程序。Linux内核中有几个示例 如果我们忘记了未捕获异常的风险(如果有的话),用C++11原子替换它们有意义吗?或者,有可能吗?正如我在阅读参考资料时所理解的那样,std::atomic设计用于管理对内存的多线程访问(并发等)。但正如我所知,正如您所说,volatile是为内存映射I/O和信号处理等功能而设计的。因此,volatile对原子访问没有影响,如果单独使用,也无法解决原子等多线程访问问题。反之亦

据我所知,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,那么它就可以将其转换为一条指令,而不依赖于您的程序在这个过程中使用了多少线程和原子。如果您的程序使用易失性变量,则情况并非如此


<>编辑:例如,显示一些可允许的(可能是意外的)编译器允许应用到原子循环变量的优化。

异常与它有什么关系?一些人,包括莱纳斯TurvDS,在C++中看到异常是它最关键的缺陷之一,尤其是用于编写内核代码。我只是想澄清一下,这样的争论超出了我的问题范围。是的,但是原子学与异常有什么关系?我们可能必须做出工程决定,放弃使用
std::atomic
,用于内存映射I/O,这通常在内核空间中使用,如果(1)至少有一个方法(间接)抛出异常,并且(2)我们没有一个好的方法在内核代码中管理它。在像Linux这样的单片内核上,我们必须特别小心。无论如何,这超出了我的问题范围。我明白了。据我所知,所有方法都有
noexcept(true)
规范,因此不允许任何异常逃逸。从理论上讲,这不会阻止他们在内部使用异常,但我想不出一个原因,为什么实际的实现会希望这样做(当然,您必须检查标准库实现的文档/代码以确保)。“反之亦然-原子不提供volatile的特性。”你没有提供任何支持此声明的理由。另外,请记住,当我们谈论
std::atomic
volatile
时,它们99.99%的使用仅限于CPU的本机整数,这些整数自然是原子的(如果你有任何非玩具反例,我会感兴趣。)@nodakai-
std::atomic
不仅仅是关于变量的部分读/写,但也涉及多CPU系统中的缓存一致性。您的
volatile
内存映射I/O可能位于非缓存内存区域,因此完全不同。@BoPersson未缓存MMIO是否会使
std::atomic
的任何假设无效?你是说效率低下吗?那么,使用
std::memory\u order\u relaxed
怎么样?@nodakai也可以查看这篇文章@VolAnd,当网站配备搜索功能时,很容易发布一个指向“相关”问答的链接,但不会立即为你的答案增加价值。
std::atomic
的什么属性使其无法用于MMIO?显然,发出内存屏障(可能伴随
std::atomic
)不会以任何方式损坏它。(@MikeMB和@marko已经提出了一点。)你可以声称,这可能是真的。但是它必须有一个有效的推理来支持。
std::atomic
中缺少了
volatile
的什么属性?不假设内存具有传统的加载/存储语义,并且没有其他副作用。在许多内存映射I/O设备中,读取和写入都有副作用(例如,从寄存器读取会取消断言和中断线,或重置其他寄存器)。@MikeMB@marko我明白了,所以尽管使用
void
-返回函数是有意义的,其主体是从MMI/O读取的单个
volatile
,当我们用
std::atomic::load
替换它时,即使使用
std::memory\u order\u seq\u cst
,理论上也可以得到一个真正的NOP——这是正确的吗?@nodakai:差不多。它仍然会发出内存限制(在×86上,编译器限制可能就足够了),但是是的,可以优化实际负载。@MikeMB点,限制(如果有的话)不会