Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/258.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#bool是原子的,为什么volatile是有效的_C#_Multithreading_Boolean_Atomic_Volatile - Fatal编程技术网

C#bool是原子的,为什么volatile是有效的

C#bool是原子的,为什么volatile是有效的,c#,multithreading,boolean,atomic,volatile,C#,Multithreading,Boolean,Atomic,Volatile,在C#中,我们知道bool是原子的-那么为什么将其标记为volatile是有效的呢?两者之间的区别是什么?一个好的(甚至是实际的)用例是什么 bool _isPending; 与 volatile bool _isPending; // Is this realistic, or insanity? 我已经做了一些阅读和研究,我正在努力确保我完全理解这两者的内在运作。我想了解什么时候使用一个与另一个比较合适,或者仅仅使用bool就足够了。如果前面或后面的代码中有变量更新,并且更新的顺序很关键

C#中,我们知道
bool
是原子的-那么为什么将其标记为
volatile
是有效的呢?两者之间的区别是什么?一个好的(甚至是实际的)用例是什么

bool _isPending;

volatile bool _isPending; // Is this realistic, or insanity?

我已经做了一些阅读和研究,我正在努力确保我完全理解这两者的内在运作。我想了解什么时候使用一个与另一个比较合适,或者仅仅使用
bool
就足够了。

如果前面或后面的代码中有变量更新,并且更新的顺序很关键,然后将该字段标记为volatile将确保在任何以前的更新之后和任何后续更新之前对该字段进行更新

换句话说,如果
\u isPending
volatile
,则编译器不会导致这些指令以不同的顺序执行:

_someVariable = 10;
_isPending = true;
_someOtherVariable = 5;
无论是多线程还是非多线程,如果我们编写的代码根据相邻行中的这些更新是否以指定的顺序发生而中断,那么一定是出了问题。我们应该问为什么这个顺序很重要。(如果有这样一个重要的场景,想象一下试图在注释中解释它,这样就不会有人对代码进行破坏性的更改。)

对于几乎所有阅读上述代码的人来说,这些操作的顺序似乎根本不重要。如果它们真的很重要,那就意味着其他阅读我们代码的人不可能理解正在发生的事情。他们可以进行一些重构,对代码行重新排序,并在不知情的情况下破坏一切。当他们测试它时,它甚至可能工作,然后在部署它时不可预测地和不一致地失败

我同意你链接的答案:

坦率地说,我不鼓励你做一个不稳定的领域。不稳定的 字段是你正在做一些完全疯狂的事情的标志:你是 试图在两个不同的线程上读写相同的值 没有把门锁好


我想我没有直接回答这个方向
volatile
对类型(包括
bool
)有效,因为可以对该类型执行原子操作<代码>易失性可防止编译器优化。根据
volatile
的文档

这样可以确保字段中的最新值在 一直都是

但是,如果字段不能以32位或更少的形式表示,那么阻止编译器优化也不能保证这一点

在C#中,我们知道布尔是原子的——那么为什么将其标记为volatile是有效的呢?两者之间的区别是什么?一个好的(甚至是实际的)用例是什么

bool _isPending;
假设您的问题是,您相信
volatile
使访问原子化。但是波动性和原子性是完全不同的东西,所以不要把它们混为一谈

易变性是指编译器和运行时被限制进行某些优化的属性,这些优化涉及到在时间上向前和向后移动变量的读写(相对于彼此),更一般地说,是相对于其他重要事件(例如启动和停止线程、运行构造函数等)。请参阅C#规范,以获取有关如何针对可见副作用重新安排操作的详细列表

原子性是一种属性,即一个特定的操作只能被观察为未开始或完全完成,并且永远不会“完成一半”

正如你从定义中所看到的,这两件事彼此没有任何关系

在C#中,所有对大小为4或更小的引用、bool和整数类型的访问都保证是原子的

现在,在C#中,原子性和波动性之间存在一些轻微的非正交性,因为只有原子类型的字段可以标记为波动性。例如,您可能无法创建易失性双精度。如果说“我们将限制读写操作的优化方式,但仍然允许撕裂”,那将是非常奇怪和危险的。由于波动性不会导致原子性,所以您不希望仅仅因为操作也是波动性的,就让用户认为操作是原子的

您应该阅读我的一系列文章,这些文章更详细地解释了这些东西之间的区别,以及volatile的实际用途,以及为什么您几乎不了解如何安全地使用它

如果您认为在阅读了所有这些之后您理解了波动性,那么我邀请您尝试解决我在这里提出的难题:


我非常确定,对于每个
volatile bool
用例,都存在另一个更优化的解决方案。所以在理论上,布尔永远是足够的。在理论上,理论和实践没有区别。但实际上情况并非如此。volatile bool是安全发布数据的最便宜、最快的方法(最简单的例子是退出标志)。@vmatm只有在环境中某个地方有bug时才使用。在这种情况下,两者在理论和实践上存在巨大差异versions@Voo你能说得更具体些吗?可能是一些文章、博客文章或MDSN?Volatile不仅仅是禁止指令的重新排序!简化的it为订购和可见性提供了保证。仅仅因为您以正确的顺序执行上述指令通常不会保证“预期”结果(它可能在x86上工作,但这是规则的例外)。这只会强化这一点。如果代码依赖于volatile的行为,那么它天生就更容易失败。如果他们只是使用了一个锁,那么它在哪个处理器上运行就无关紧要了。如果你正确地使用volatile,你在每个平台上都会得到相同的行为