C# bool是原子的,为什么volatile有效
C# bool is atomic, why is volatile valid
在 C# 中,我们知道 bool
是原子的 - 那么为什么将其标记为 volatile
是有效的?两者有什么区别,什么是好的(甚至实用的)用例?
bool _isPending;
对战
volatile bool _isPending; // Is this realistic, or insanity?
我已经阅读了一些资料 here and here,我正在努力确保我完全理解这两者的内部工作原理。我想了解什么时候使用一个比较合适,或者仅 bool
就足够了。
如果前面或后面的代码中有对变量的更新,并且更新发生的顺序很重要,那么将字段标记为 volatile
将确保对该字段的更新发生在任何之后之前的更新和任何后续更新之前。
换句话说,如果_isPending
是volatile
,那么编译器不会导致这些指令以不同的顺序执行:
_someVariable = 10;
_isPending = true;
_someOtherVariable = 5;
无论是否是多线程,如果我们编写的代码根据相邻行中的这些更新是否按指定顺序发生而中断,那么就会出现问题。我们应该问为什么这个顺序很重要。 (如果有一个场景很重要,想象一下尝试在评论中解释它,这样就没有人对代码进行重大更改。)
对于几乎所有阅读上面代码的人来说,这些操作的顺序似乎根本不重要。如果它们确实重要,那就意味着阅读我们代码的其他人不可能理解发生了什么。他们可以进行一些重构,重新排列这些代码行,并在不知情的情况下破坏所有内容。它甚至可能在他们测试时工作,然后在部署时出现不可预测和不一致的失败。
我同意 Eric Lippert's comment 您链接的答案:
Frankly, I discourage you from ever making a volatile field. Volatile
fields are a sign that you are doing something downright crazy: you're
attempting to read and write the same value on two different threads
without putting a lock in place.
我想我没有直接回答方向。 volatile
对类型有效(包括 bool
),因为可以对该类型执行原子操作。 volatile
防止编译器优化。根据 volatile
、
的文档
This ensures that the most up-to-date value is present in the field at
all times.
但是,如果该字段不能以 32 位或更少的位表示,那么阻止编译器优化无论如何都不能保证这一点。
In C#, we know that a bool is atomic - then why is it valid to mark it as volatile? what is the difference and what is a good (or even practical) use-case for one versus the other?
你的问题的假设是你相信 volatile
使访问原子化。但是波动性和原子性是完全不同的东西,所以不要把它们混为一谈了。
波动性是 属性, 编译器和运行时被限制进行某些优化,涉及相对于彼此在时间上向前和向后移动变量的读写,更一般地说,关于其他重要事件,例如启动和停止线程、运行 构造函数等。请参阅 C# 规范以获取有关如何根据可见的副作用重新排序操作或不重新排序操作的详细列表。
原子性是属性,即一个特定的操作只能被观察为未开始或完全完成,而永远不会"halfway done"。
正如您从定义中看到的那样,这两者之间 没有任何关系。
在 C# 中,所有对大小为 4 及更小的引用、布尔值和整数类型的访问都保证是原子的。
现在,在 C# 中,原子性和易变性之间存在一些轻微的非正交性,因为 只有原子类型的字段可以标记为易变性。例如,您可能不会制作 volatile double。说 "we're going to restrict how reads and writes may be optimized but still allow tearing" 真的很奇怪也很危险。由于易变性不会 导致 原子性,您不希望让用户仅仅因为操作也是易变性就认为它是原子性的。
您应该阅读我的系列文章,其中更详细地解释了这些东西之间的区别,volatile 的实际作用,以及为什么您对安全使用它的了解还不够多。
https://ericlippert.com/2011/05/26/atomicity-volatility-and-immutability-are-different-part-one/
https://ericlippert.com/2011/05/31/atomicity-volatility-and-immutability-are-different-part-two/
https://ericlippert.com/2011/06/16/atomicity-volatility-and-immutability-are-different-part-three/
如果你认为你在阅读所有内容后了解波动性,我邀请你尝试解决我在这里提出的难题:
在 C# 中,我们知道 bool
是原子的 - 那么为什么将其标记为 volatile
是有效的?两者有什么区别,什么是好的(甚至实用的)用例?
bool _isPending;
对战
volatile bool _isPending; // Is this realistic, or insanity?
我已经阅读了一些资料 here and here,我正在努力确保我完全理解这两者的内部工作原理。我想了解什么时候使用一个比较合适,或者仅 bool
就足够了。
如果前面或后面的代码中有对变量的更新,并且更新发生的顺序很重要,那么将字段标记为 volatile
将确保对该字段的更新发生在任何之后之前的更新和任何后续更新之前。
换句话说,如果_isPending
是volatile
,那么编译器不会导致这些指令以不同的顺序执行:
_someVariable = 10;
_isPending = true;
_someOtherVariable = 5;
无论是否是多线程,如果我们编写的代码根据相邻行中的这些更新是否按指定顺序发生而中断,那么就会出现问题。我们应该问为什么这个顺序很重要。 (如果有一个场景很重要,想象一下尝试在评论中解释它,这样就没有人对代码进行重大更改。)
对于几乎所有阅读上面代码的人来说,这些操作的顺序似乎根本不重要。如果它们确实重要,那就意味着阅读我们代码的其他人不可能理解发生了什么。他们可以进行一些重构,重新排列这些代码行,并在不知情的情况下破坏所有内容。它甚至可能在他们测试时工作,然后在部署时出现不可预测和不一致的失败。
我同意 Eric Lippert's comment 您链接的答案:
Frankly, I discourage you from ever making a volatile field. Volatile fields are a sign that you are doing something downright crazy: you're attempting to read and write the same value on two different threads without putting a lock in place.
我想我没有直接回答方向。 volatile
对类型有效(包括 bool
),因为可以对该类型执行原子操作。 volatile
防止编译器优化。根据 volatile
、
This ensures that the most up-to-date value is present in the field at all times.
但是,如果该字段不能以 32 位或更少的位表示,那么阻止编译器优化无论如何都不能保证这一点。
In C#, we know that a bool is atomic - then why is it valid to mark it as volatile? what is the difference and what is a good (or even practical) use-case for one versus the other?
你的问题的假设是你相信 volatile
使访问原子化。但是波动性和原子性是完全不同的东西,所以不要把它们混为一谈了。
波动性是 属性, 编译器和运行时被限制进行某些优化,涉及相对于彼此在时间上向前和向后移动变量的读写,更一般地说,关于其他重要事件,例如启动和停止线程、运行 构造函数等。请参阅 C# 规范以获取有关如何根据可见的副作用重新排序操作或不重新排序操作的详细列表。
原子性是属性,即一个特定的操作只能被观察为未开始或完全完成,而永远不会"halfway done"。
正如您从定义中看到的那样,这两者之间 没有任何关系。
在 C# 中,所有对大小为 4 及更小的引用、布尔值和整数类型的访问都保证是原子的。
现在,在 C# 中,原子性和易变性之间存在一些轻微的非正交性,因为 只有原子类型的字段可以标记为易变性。例如,您可能不会制作 volatile double。说 "we're going to restrict how reads and writes may be optimized but still allow tearing" 真的很奇怪也很危险。由于易变性不会 导致 原子性,您不希望让用户仅仅因为操作也是易变性就认为它是原子性的。
您应该阅读我的系列文章,其中更详细地解释了这些东西之间的区别,volatile 的实际作用,以及为什么您对安全使用它的了解还不够多。
https://ericlippert.com/2011/05/26/atomicity-volatility-and-immutability-are-different-part-one/
https://ericlippert.com/2011/05/31/atomicity-volatility-and-immutability-are-different-part-two/
https://ericlippert.com/2011/06/16/atomicity-volatility-and-immutability-are-different-part-three/
如果你认为你在阅读所有内容后了解波动性,我邀请你尝试解决我在这里提出的难题: