看了一个之后 of https://stackoverflow.com/questions/78172/using-c-pthreads-do-shared-variables-need-to-be-volatile 问题 https://stackoverflow.com/questions/23449562/when-would-you-need-a-volatile-pointer and https://stackoverflow.com/questions/2478397/atomic-swap-in-gnu-c/2478520#2478520 their https://stackoverflow.com/a/44243426/706054 answers https://stackoverflow.com/a/2485733/706054,我的印象是对于 C 语言中“易失性”关键字的确切含义还没有达成广泛的共识。
就连标准本身似乎也不够明确,无法让大家达成共识这是什么意思 http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1956.htm.
其他问题包括:
- 它似乎提供不同的保证,具体取决于您的硬件和编译器。
- 它影响编译器优化,但不影响硬件优化,因此在自己进行运行时优化的高级处理器上,甚至不清楚编译器是否can阻止任何你想阻止的优化。 (一些编译器确实会生成指令来阻止某些系统上的某些硬件优化,但这似乎没有以任何方式标准化。)
总结一下这个问题,(在阅读了大量内容之后)“易失性”似乎保证了类似的内容:该值不仅会从寄存器读取/写入,而且至少会按照代码中出现的读取/写入顺序读取到内核的 L1 缓存。但这似乎毫无用处,因为在同一线程中从寄存器读取/写入寄存器已经足够了,而与 L1 缓存协调并不能保证与其他线程的协调有任何进一步的保证。我无法想象什么时候只与 L1 缓存同步变得很重要。
USE 1
唯一得到广泛认可的 volatile 似乎是用于旧的或嵌入式系统,其中某些内存位置被硬件映射到 I/O 功能,例如内存中控制(直接在硬件中)灯的位,或者内存中的一个位可以告诉您键盘按键是否按下(因为它是由硬件直接连接到按键的)。
看起来“use 1”不会出现在目标包括多核系统的可移植代码中。
USE 2
与“use 1”没有太大区别的是可以由中断处理程序随时读取或写入的内存(可以控制灯或存储来自按键的信息)。但为此我们已经遇到了一个问题,根据系统的不同,中断处理程序可能会运行 https://stackoverflow.com/q/33955582/706054 不同的核心 https://stackoverflow.com/a/25153972/706054 with 它自己的内存缓存 https://stackoverflow.com/a/954069/706054,并且“易失性”并不能保证所有系统上的缓存一致性。
So “use 2”似乎超出了“volatile”所能提供的范围。
USE 3
我看到的唯一其他无可争议的用途是通过指向同一内存的不同变量来防止访问错误优化,而编译器没有意识到这是同一内存。但这可能是无可争议的,因为人们没有谈论它——我只看到一次提到它。我认为 C 标准已经认识到“不同”指针(如函数的不同参数)可能指向相同的项目或附近的项目,并且已经指定编译器必须生成即使在这种情况下也能工作的代码。然而,我无法在最新的(500 页!)标准中快速找到这个主题。
So “use 3”可能不存在 at all?
因此我的问题是:
“易失性”是否能保证多核系统的可移植 C 代码中的任何内容?
编辑——更新
浏览完后最新标准 https://web.archive.org/web/20181230041359if_/http://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf,看起来答案至少是very有限的是:
1、标准反复规定了对特定类型“volatile sig_atomic_t”的特殊处理。然而,该标准还指出,在多线程程序中使用信号函数会导致未定义的行为。因此,这个用例似乎仅限于单线程程序及其信号处理程序之间的通信。
2. 该标准还规定了与 setjmp/longjmp 相关的“易失性”的明确含义。 (重要的示例代码在其他中给出问题 https://stackoverflow.com/questions/1393443/setjmp-longjmp-and-local-variables and answers https://stackoverflow.com/questions/7996825/why-volatile-works-for-setjmp-longjmp.)
所以更精确的问题变成:
除了 (1) 允许单线程程序从其信号处理程序接收信息,或 (2) 允许 setjmp 代码查看 setjmp 之间修改的变量之外,“易失性”是否能保证多核系统的可移植 C 代码中的任何内容还有longjmp?
这仍然是一个是/否问题。
如果“是”,如果您能展示一个无错误的可移植代码的示例,如果省略“易失性”,该代码就会出现错误,那就太好了。如果“否”,那么我认为对于多核目标,编译器可以自由地忽略这两种非常具体的情况之外的“易失性”。