为什么POSIX mmap没有返回volatile void *?

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

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

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

贯穿许多软件系统的深刻假设是大多数程序员都是顺序程序员。 这最近才开始改变。

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

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

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

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

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

还有这个:

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

根据您的建议, 普通案例中的用户必须抛弃易失性。

易失性只会覆盖一次读取(取决于架构可能是32位或其他东西,因此非常有限。通常你需要编写超过1个机器字,你无论如何都要介绍一些一种锁定。

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

因此 – mmap()尝试处理这些事情是没有用的,最好让程序员如何处理对内存的访问并在需要时将指针标记为volatile – 如果内存是共享的 – 你需要让所有参与者合作并意识到他们如何更新内存相对于彼此 – 超出mmap范围的东西,以及挥发性无法解决的东西。

我不认为volatile会做你认为它做的事情。

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

该函数返回一个void *,但它不会被更新,因此调用volatile是没有意义的。 即使您将值赋给本地volatile void *,也不会获得任何结果。

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

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

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

而且,既然你无论如何需要转换为char *或任何数据类型,那么也许这是指定波动率的正确位置。 因此,所定义的API很好地侧重于标记存储器的责任 – 在脚下/易失性。

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