volatile只是不适合任何范例

Lor*_*one 0 c c++ mutex volatile thread-safety

我是唯一这么认为的人吗?[真正的问题在一秒钟内.]

除了对它的巨大混淆,以及它与互斥或其他锁定机制的混合,当我处理线程安全情况时,我总是不得不放弃任何使用volatile,因为它根本没有做任何有用的事情.

volatile"禁止对读/写进行任何重新排序或缓存",但volatile 只要标记单个对象(并将其污染,因为它不再是"普通"对象),这并没有多大用处.

考虑一下:

Thread A            Thread B
reads vars
                    locks mutex (gets access)
locks mutex (waits)
                    writes some vars
                    releases mutex
reads vars again
releases mutex
Run Code Online (Sandbox Code Playgroud)

现在,编译器可能希望优化两个线程A的读取,从而将一些结果保存在寄存器中.你说我应该宣布那些变量为volatile.我说我不想标记所有内容volatile,因为它volatile是透明的,我必须复制50%的代码才能支持volatile类型.您()说锁定互斥锁(至少是POSIX互斥锁)是编译器识别并正确管理的东西,要么是对库的调用(编译器无法访问),这可能会改变世界,所以编译器这样的电话会议后不会做任何事情.我说这是依赖于实现的,非常低级别的东西(我不想浏览开发文档以进行日常编程).更糟糕的是,如果由于某种原因,出于某种原因,"外部库"由于任何合法的原因而变得可供编译器访问(可能是作者在必须包含在头文件中的模板中转换函数......无论如何),它会突然改变.

所以,在我看来,volatile完全没用(和误导),除非是一些非常低级别的东西(设备读取可能,但我不能胜任这样的领域).

更好的方法是明确告诉编译器它必须放弃任何关于任何变量的假设,并且每次后续读取必须是从内存中读取的真实内容.但是我无法想象比调用虚拟外部函数更好的事情,这会产生我之前概述的相同问题.有一种优雅的方式吗?

Bil*_*nch 8

我使用低级别的东西,这是一个有用的例子.

volatile uint32_t *foo = <<<a register on a pci device>>> 
Run Code Online (Sandbox Code Playgroud)

有可能在foo多次阅读时,我会得到不同的结果.这是因为外部源(pci设备)正在修改它.例如,foo可能意味着当前时间.

当我写信时foo,它可能与可能出现的内容几乎没有关系.例如,我可能有一个存储一些警报位的寄存器.我会写那些位来清除它们.因此,如果寄存器foo具有值0x72,我可能会写入0x2寄存器,这可能导致该寄存器中的结果值0x70.

volatile 允许我使用这些语义.