Java's volatile in C?
我知道Java中volatile的使用。
那是(基于维基百科的文章):
There is a global ordering on the reads and writes to a volatile
variable. This implies that every thread accessing a volatile field
will read its current value before continuing, instead of
(potentially) using a cached value.
我也知道C中存在volatile关键字,但是在完全不同的上下文中,主要用于内存映射的I / O。
所以我想知道,在C中是否存在像Java的volatile这样的结构?这将防止
读取变量的缓存值?
如果C中不存在它,也许是否有一个具有这样构造的库,例如pthread?
- 您希望使用内存屏障来排序读/写,但是它们是特定于平台的,而不是C的一部分
-
@awoodland我不希望我的所有线程在继续之前在特定点互相等待。从我得到的结果来看,这就是内存屏障的作用。我只想在读取变量时要确保正在读取此变量的最新值,而不是已缓存的值。
-
@Fooko您在想什么不同的东西。内存屏障基本上是对CPU的低级指令。 Javas volatile通过内存屏障实现
-
kernel.org/doc/Documentation/memory-barriers.txt对障碍有很好的讨论
-
@awoodland很好的链接。好的,易于理解的摘要。
在C语言中,
volatile基本上是一种过时,旨在用于完全不同的场景,并且对多线程编程没有用处。出于某种原因,甚至最新的c标准也无法赋予它更多的含义,而是不得不发明一个新的关键字。
提醒您,这意味着C标准所定义的volatile是无用的,编译器可能会为您提供其他保证(我知道MS VC可以提供,并且我认为它与Java中的volatile提供的保证基本相同),但这意味着该程序被锁定到该编译器。大多数编译器还具有一些用于插入内存屏障的内在函数,这些内在函数更加明确,但本质上也无法移植。
实际上,您最好使用一些更高级别的线程库,该库为该工作提供正确的工具。例如。 POSIX为您提供了低级内存屏障afaik。
在c站点上,最好使用0x11-标准确实提供了std::atomic_thread_fence和原子变量。请注意,尽管c 0x11内存模型与Java内存模型并不相同,所以在移植时必须要小心。
- 感谢您的回答。从我得到的结果来看,正如我已经对林地所说的,障碍/栅栏是一个不同的概念。我认为壁垒用于使所有线程在所有其他线程都在特定点上等待之后才能继续工作。我不想让我的线程等待其他线程,我只是想让他们读取的所有内容与当时内存中的内容一致,而不是某些缓存的值一致。当然,我也不想取消限制,但是我仍然不明白在这方面障碍有什么帮助?
-
@Fooko在此处查看awoodlands和我对您的观点的回答。您似乎在想Javas CyclicBarrier。一个是一个非常低级的概念,另一个是大多数线程库提供的相当高级的结构。 Wiki文章很快介绍了基本知识,但是乍一看,awoodlands链接似乎真的很不错。
-
@Fooko R .:内存屏障/屏障不是线程屏障。内存围栏是一种特殊的指令,不允许相对于围栏本身对装载或存储或两者进行重新排序。因此,实际上,栅栏之前的负载无法与栅栏之后的负载重新排序。
-
好的,我将同时阅读Wiki文章和awoodlands链接。谢谢! @Tudor,但是看来我每次在程序中读写后都应该使用围栏。例如。 read fence write fence read fence read fence ... 难道没有一种更简单的方法让编译器(硬件)现在不希望使用任何重新排序吗?
-
AFAIK C11内存模型与C 11内存模型基本相同。
-
@Tudor阅读Wiki文章后,我想在每次读取/加载后我都应该写asm("mfence");。那不是很受虐吗?
-
@Fooko那么,当您需要内存障碍时,您必须了解自己。通常,最好是将这些低级内容留给知道他们在做什么的人:)此外,取决于包括asm指令的编译器会禁用所有/大多数优化(gcc具有避免这种情况的复杂的asm系统,MSVC不会这样做) ),这本身并不是一个很好的解决方案。
-
谢谢Voo的回答:)真的有很大帮助。
volatile的行为不一定是不同的;平台和上下文是不同的。您在问题中特别提到了内存映射设备。如果您有一个内存映射的设备(例如某些硬件)可以翻转代码中由变量表示的寄存器,那么显然您需要一种方式来表明这一点。如果您不这样做,则编译器将始终在这样的假设下工作,即唯一可以更改代码的系统就是您的程序,并且可以对其进行优化。
一个很好的例子是,如果您在决策或控制流情况下使用变量。如果此变量从未在代码中直接操作过,而是可能被信号或某些内存映射的硬件翻转,则编译器可能会将决策条件优化为布尔值,因为它将假定该值不会改变。因此,当硬件翻转该值时,由于编译器的优化,它不会反映在正在运行的代码中。
Java " caches "基本上是相同的行为。断开连接的原因似乎是您没有在虚拟机内部运行的C语言和Java JIT字节代码之间架起一座桥梁。 Java从C继承其volatile行为,但是由于运行时上下文,此行为的后果完全不同。