11

Mmap 返回 void*,但不返回volatile void*. 如果我使用 mmap 来映射共享内存,那么另一个进程可能正在写入该内存,这意味着从同一内存位置进行的两次后续读取可能会产生不同的值—— volatile 的确切情况。那么为什么它不返回一个 volatile void* 呢?

我最好的猜测是,如果您有一个专门写入共享内存段的进程,它不需要通过易失性指针查看共享内存,因为它总是对当前存在的内容有正确的理解;编译器为防止冗余读取所做的任何优化都无关紧要,因为没有其他东西可以写入和更改其脚下的值。还是有其他历史原因?我倾向于说返回volatile void*将是一个更安全的默认值,那些想要这种优化的人可以手动转换为 void*。

POSIX mmap 说明: http: //opengroup.org/onlinepubs/007908775/xsh/mmap.html

4

6 回答 6

8

实现共享内存只是mmap(). 事实上,最常见的用途是创建私有映射,包括匿名的和文件支持的。这意味着,即使我们接受了您关于需要volatile-qualified 指针来访问共享内存的论点,这种限定符在一般情况下也是多余的。

请记住,您始终可以在不强制转换的情况下final 限定符添加到指针类型,但不能删除它们。因此,使用当前mmap()声明,您可以同时执行以下操作:

volatile char *foo = mmap();  /* I need volatile */

还有这个:

char *bar = mmap();  /* But _I_ do not */

根据您的建议,普通情况下的用户将不得不抛弃 volatile。

于 2010-07-09T01:01:38.647 回答
7

贯穿许多软件系统的根深蒂固的假设是,大多数程序员都是顺序程序员。这种情况最近才开始改变。

mmap有几十种与共享内存无关的用途。如果程序员正在编写多线程程序,他们必须采取自己的步骤来确保安全。使用互斥锁保护每个变量不是默认设置。同样,mmap假设另一个线程将对同一个共享内存段进行有争议的访问,或者甚至不假设这样映射的段将被另一个线程访问。

我也不相信标记mmapas的回归volatile会对此产生影响。程序员仍然必须确保访问映射区域的安全性,不是吗?

于 2010-07-08T20:25:06.633 回答
4

易失性只会涵盖一次读取(取决于架构可能是 32 位或其他内容,因此非常有限。通常您需要编写超过 1 个机器字,并且无论如何您都必须引入一些某种锁定。

即使它是易失性的,你也可以很容易地让 2 个进程从同一个内存读取不同的值,只需要一个 3. 进程在从 1. 进程读取和从 2 读取之间的纳秒内写入内存. 进程(除非您可以保证 2 个进程在几乎完全相同的时钟周期内读取相同的内存。

因此 - mmap() 尝试处理这些事情是非常无用的,最好留给程序员如何处理对内存的访问并在需要时将指针标记为易失性 - 如果内存是共享的 - 你需要让所有相关方合作并了解他们如何更新彼此相关的内存 - 超出 mmap 范围的内容,以及 volative 无法解决的问题。

于 2010-07-08T20:26:47.287 回答
1

我不认为volatile你认为它会做。

基本上,它只是告诉编译器不要通过将变量的值存储在寄存器中来优化变量。这会强制它在您每次引用它时检索该值,如果另一个线程(或其他线程)可以在此期间更新它,这是一个好主意。

该函数返回一个 void*,但它不会被更新,所以称它为 volatile 是没有意义的。即使您将值分配给本地 volatile void*,也不会获得任何结果。

于 2010-07-08T20:20:27.610 回答
1

类型volatile void *orvoid * volatile是无意义的:您不能取消引用 a void *,因此为其指定类型限定符是没有意义的。

而且,由于您无论如何都需要转换为char *或任何您的数据类型,那么也许这是指定波动性的正确位置。因此,定义的 API 很好地回避了标记内存在你的脚下可更改/易失性的责任。

也就是说,从宏观 POV 来看,我同意你的观点:mmap 应该有一个返回类型,说明编译器不应该缓存这个范围。

于 2010-07-08T23:14:11.257 回答
0

出于性能原因,它可能是这样做的,默认情况下不提供任何额外内容。如果您知道在您的特定架构上写入/读取不会被处理器重新排序,您可能根本不需要 volatile(可能与其他同步结合使用)。编辑:这只是一个例子 - 可能有多种其他情况,您知道每次访问内存时都不需要强制重新读取。

如果您需要确保每次访问时都从内存中读取所有地址,请自行将 const_cast(或 C 样式转换)volatile 转换为返回值。

于 2010-07-08T20:37:18.560 回答