【发布时间】:2018-01-26 23:28:33
【问题描述】:
我对 C 和 C++ 中volatile 语义的理解是,它将内存访问变成了(observable) side effects。每当读取或写入内存映射文件(或共享内存)时,我都希望指针是 volatile 限定的,以表明这实际上是 I/O。 (John Regehr 在volatile 的语义上写了一篇非常好的article)。
此外,我希望使用像 memcpy() 这样的函数来访问共享内存是不正确的,因为签名表明 volatile 限定已被抛弃,并且内存访问不被视为 I/O。
在我看来,这是一个支持 std::copy() 的论点,其中 volatile 限定符不会被丢弃,并且内存访问被正确地视为 I/O。
但是,我使用指向 volatile 对象的指针和 std::copy() 访问内存映射文件的经验是,它比仅使用 memcpy() 慢几个数量级。我很想得出结论,也许 clang 和 GCC 在对待volatile 时过于保守。是这样吗?
如果我想遵循标准的字母并将其恢复为我所依赖的语义,关于访问共享内存有什么指导 volatile?
来自标准[intro.execution] §14的相关引用:
读取由 volatile glvalue 指定的对象,修改 对象,调用库 I/O 函数,或调用一个函数 这些操作中的任何一个都是副作用吗,它们是变化 在执行环境的状态下。表达式的评估 (或子表达式)通常包括两个值计算 (包括为 glvalue 确定对象的身份 评估并获取先前分配给对象的值 prvalue评估)和副作用的开始。当一个电话 库 I/O 函数通过 volatile 左值返回或访问 评估副作用被认为是完整的,即使有些 调用隐含的外部动作(例如 I/O 本身)或 volatile 访问可能尚未完成。
【问题讨论】:
-
在处理 volatile 时,可能需要在 memcpy 前后添加内存屏障。
-
请澄清您的意思是“易失性指针”还是“指向易失性数据的非易失性指针”?
-
您同时标记了 C 和 C++,但谈论的是“标准”。
-
@Arvid:你混淆了线程、进程、内存访问和信念。
-
@knivil 我只想通过 mmap 映射的内存访问磁盘上的文件。而已。我不相信“内存屏障”是 C++ 的概念(有 launder 和 std::experimental::barrier)。我标记了“语言律师”,以表明我的主要兴趣不是一些当代编译器如何在一些流行的架构上生成代码,而是如何以 C++(或 C)抽象正确捕获和执行的方式表达意图机器。对于通过 mmap() 读取和写入文件的目的,多次加载或存储并不是真正的问题(给定一个 std::copy)
标签: c++ c language-lawyer volatile mmap