【问题标题】:What's the difference of the usage of volatile between C/C++ and C#/Java?C/C++ 和 C#/Java 之间 volatile 的用法有什么区别?
【发布时间】:2013-11-24 06:11:43
【问题描述】:

我在许多参考文献中发现它提到 C/C++ 中的 volatile 很弱,可能会在多处理器上的并发环境中引起问题,但它 (volatile) 可以用作不同 CPU 之间的通信机制C#/Java。看起来这个关键字在 C#/Java 中比在 C/C++ 中更严格,但它们之间有什么区别/影响?

这里是 C/C++ 中volatile 的引用。 Why is volatile not considered useful in multithreaded C or C++ programming?

【问题讨论】:

标签: c# java c++ c concurrent-programming


【解决方案1】:

volatile 关键字对语言和实现它的平台具有很大的主观性。虽然 Java 在所有架构中都提供了一致的 volatile 行为,但对于直接编译到本机机器平台的语言(例如 C/C++),情况并非如此。让我们试着理解为什么会这样。

设 a, b 是一组程序动作 P 的成员,并且 v_{n} (a) 是将波动性要求应用于动作的函数,其中下标 _n 表示第 _n 次迭代,其中一个 volatile action 被应用,并且 \rightarrow 是前面的操作符,这在前面已经解释过了。对于所有程序操作,以下规则都成立:

v_n(a) \rightarrow v_{n+1}(a)

a \rightarrow v_n(b) \Rightarrow a \rightarrow v_{n+i}(b) 其中 i \in \mathbb{N}

规则 1 说所有 volatile 函数都强制执行总顺序,其中函数 v_{n} (a) 总是在 v_{n+1} (a) 之前,其中规则 2 说如果动作 a 在 volatile 函数之前在第 _n 次迭代的动作 b 上,动作 a 必须先于应用于 b 的所有后续 volatile 函数。

这在 Java 中是一个非常强的内存要求,实际上它比 C/C++ 强得多。 C/C++ 语言规范对内存排序没有这种限制,而是由编译器实现来决定如何围绕易失性操作对非易失性操作进行排序。

让我们通过一个简单的代码示例来考虑这些规则如何影响程序执行:

int a = 0;
int b = 0;
volatile int count = 0;

a  = 1;
count = 1;
b = 2;
count = 2;

在 C/C++ 中,volatile 关键字仅保证 count 变量不能相互重新排序,即。如果 count == 2,则 count = 1 必须在它之前。但是,既不能保证 a == 1,也不能保证 b == 2。

在 Java 中,给定上面定义的更强保证,那么如果 count == 1,那么断言 a == 1 必须为真。同样,如果 count == 2 则断言 a == 1 && b == 2 必须为真。这就是 Java 提供 C/C++ 不提供的严格内存保证的含义。

但这并不意味着 C/C++ 的行为方式与 Java 不同。是否这样做取决于(1)编译器是否执行任何可能以令人惊讶的顺序但合法顺序的代码重新排序,以及(2)底层机器架构是否支持相同的严格内存顺序,前提是编译器不会执行任何令人惊讶的代码重新排序。

例如,在 gcc 上编译代码并在所有 x86 平台上设置 -O0 将符合(并且比)Java 的内存模型更严格,但其他架构(如 PowerPC、Alpha、Itanium)都支持较弱的内存模型,可以表现出程序员可能没有预料到的令人惊讶的程序行为。警告讲师!

无论如何,如果您对更多内存模型一致性规则感兴趣,您可能想观看英特尔对 x86 内存模型的解释,其中详细解释了内存排序的细微差别。尽情享受吧!

【讨论】:

【解决方案2】:

对于C#/Java,“volatile”告诉编译器一个变量的值绝不能被缓存,因为它的值可能会在程序本身的范围之外改变。然后,如果变量“超出其控制范围”发生变化,编译器将避免任何可能导致问题的优化。

C/C++ 中,开发嵌入式系统或设备驱动程序时需要“volatile”,您需要在其中读取或写入内存映射的硬件设备。特定设备寄存器的内容可能随时更改,因此您需要使用“volatile”关键字来确保此类访问不会被编译器优化掉。

【讨论】:

  • 在C/C++中,阻止编译器优化访问也意味着告诉编译器不要缓存。
  • Java:volatile关键字效果不完全。访问volatile 变量还强制发生在线程内的操作之间的关系
  • 听起来 Java 的 volatile 是具有获取-释放顺序的原子加载/存储。
【解决方案3】:

在 C/C++ 中,volatile 没有与多线程相关的特定语义,因此它在该上下文中的行为是特定于平台的。 C# 和 Java 为 volatile 提供特定的多线程语义。所以你知道你得到了什么并且可以依赖它。

【讨论】:

  • 谢谢。 volatile 在 C#/Java 中提供了哪些多线程语义?
  • @Thomson 您可以查看各个语言的文档,但基本思想是volatile 提供了 C# 和 Java 线程之间的排序和可见性。在 C 和 C++ 中,不能保证做任何事情。
猜你喜欢
  • 1970-01-01
  • 2011-05-13
  • 1970-01-01
  • 1970-01-01
  • 2010-09-08
  • 2010-12-21
  • 1970-01-01
  • 1970-01-01
  • 2011-04-05
相关资源
最近更新 更多