与使用 Interlocked 类相比,使用 volatile 关键字有什么优势吗?
换句话说,我可以用一个易失性变量做一些普通变量和 Interlocked 类无法解决的事情吗?
In other words, can I do something with a volatile variable that could not also be solved with a normal variable and the Interlocked class?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
编辑:问题很大程度上重写了
为了回答这个问题,我进一步深入研究了这个问题,发现了一些关于
易失性
和互锁
的事情我不知道。让我们澄清这一点,不仅是为了我,也是为了这次讨论和其他阅读此内容的人:易失性
读/写应该不受重新排序的影响。这仅意味着读取和写入,它不意味着任何其他操作;Interlocked
使用原子汇编指令进行 CompareExchange (cmpxchg
)、Increment (inc
) 等;互锁
有时确实使用锁:a 多处理器系统上的硬件锁定;在单处理器系统中,没有硬件锁;Interlocked
与易失性
的不同之处在于它使用全栅栏,而易失性使用半栅栏。易失性时,写入后的读取可以重新排序
代码>.
Interlocked
不会发生这种情况。VolatileRead
和VolatileWrite
具有与“易失性”相同的重新排序问题(感谢 Brian Gideon 提供的链接)。现在我们已经有了规则,我们可以定义您的问题的答案:
volatile
完成,而无法使用Interlocked
完成:a
或b
为易失性的情况下编写a = b
,但这很明显;Interlocked
来执行此操作。换句话说:使用易失性
可能不太安全,然后使用Interlocked
。易失性
比互锁
更快。语义上:不,因为
Interlocked
只是提供操作的超集,并且使用起来更安全,因为它应用了完整的防护。您无法使用volatile
做任何使用Interlocked
做不到的事情,并且可以使用Interlocked
做很多你不能用 volatile 做到这一点:作用域:是的,声明一个变量
易失性
使其对于每次访问都是易失性的。不可能以任何其他方式强制执行此行为,因此volatile
不能替换为Interlocked
。在其他库、接口或硬件可以访问您的变量并随时更新它,或者需要最新版本的情况下,这是需要的。如果您问我,最后一点是对
易失性
的实际需求,并且可能使其成为两个进程共享内存并且需要在不锁定的情况下读取或写入的理想选择。在这种情况下,将变量声明为易失性
比强制所有程序员使用Interlocked
(编译器无法强制执行)要安全得多。编辑:以下引用是我原始答案的一部分,我将其保留在 ;-)
来自 C# 编程语言 标准的引用:
更新:问题大部分被重写,更正了我原来的回答并添加了“真实”答案
EDIT: question largely rewritten
To answer this question, I dived a bit further in the matter and found out a few things about
volatile
andInterlocked
that I wasn't aware of. Let's clear that out, not only for me, but for this discussion and other people reading up on this:volatile
read/write are supposed to be immune to reordering. This only means reading and writing, it does not mean any other action;Interlocked
uses atomic assembly instructions for CompareExchange (cmpxchg
), Increment (inc
) etc;Interlocked
does use a lock sometimes: a hardware lock on multi processor systems; in uni-processor systems, there is no hardware lock;Interlocked
is different fromvolatile
in that it uses a full fence, where volatile uses a half fence.volatile
. It can't happen withInterlocked
.VolatileRead
andVolatileWrite
have the same reordering issue as `volatile (link thanks to Brian Gideon).Now that we have the rules, we can define an answer to your question:
volatile
that you cannot do withInterlocked
:a = b
wherea
orb
is volatile, but this is obvious;Interlocked
. In other words: you can be less safe withvolatile
then you can be withInterlocked
.volatile
is faster thenInterlocked
.Semantically: no, because
Interlocked
simply provides a superset of operations and is safer to use because it applies full fencing. You can't do anything withvolatile
that you cannot do withInterlocked
and you can do a lot withInterlocked
that you cannot do with volatile:Scope: yes, declaring a variable
volatile
makes it volatile for every single access. It is impossible to force this behavior any other way, hencevolatile
cannot be replaced withInterlocked
. This is needed in scenarios where other libraries, interfaces or hardware can access your variable and update it anytime, or need the most recent version.If you'd ask me, this last bit is the actual real need for
volatile
and may make it ideal where two processes share memory and need to read or write without locking. Declaring a variable asvolatile
is much safer in this context then forcing all programmers to useInterlocked
(which you cannot force by the compiler).EDIT: The following quote was part of my original answer, I'll leave it in ;-)
A quote from the the C# Programming Language standard:
Update: question largely rewritten, corrected my original response and added a "real" answer
这是一个相当复杂的话题。我发现 Joseph Albahari 的文章是更明确和准确的来源之一.NET Framework 中的多线程概念可能有助于回答您的问题。
但是,快速总结一下,就如何使用而言,
volatile
关键字和Interlocked
类之间存在很多重叠。当然,两者都远远超出了普通变量的范围。This is a fairly complex topic. I find Joseph Albahari's writeup to be one of the more definitive and accurate sources for multithreading concepts in the .NET Framework that might help answer your question.
But, to quickly summarizes there is a lot of overlap between the
volatile
keyword and theInterlocked
class as far as how they can be used. And of course both go way above and beyond what you can do with a normal variable.是的 - 您可以直接查看该值。
只要您仅使用 Interlocked 类来访问变量,那么就没有区别。 易失性的作用是告诉编译器该变量是特殊的,并且在优化时不应该假设该值没有改变。
采用此循环:
如果您在另一个线程中将
done
设置为true
,您将期望循环退出。然而,如果done没有被标记为易失性
,那么编译器可以选择意识到循环代码永远不会改变done
,并且它可以优化退出的比较。这是多线程编程的困难之一——许多问题只在某些情况下才会出现。
Yes - you can look at the value directly.
As long as you ONLY use the Interlocked class to access the variable then there is no difference. What volatile does is it tells the compiler that the variable is special and when optimizing it shouldn't assume that the value hasn't changed.
Takes this loop:
If you set
done
totrue
in another thread you would expect the loop to exit. However - if done is not marked asvolatile
then the compiler has the option to realize that the loop code can never changedone
and it can optimize out the compare for exit.This is one of the difficult things about multithread programming - many of the situations which are problems only come up in certain situations.
我不会试图成为这个主题的权威,但我强烈建议您看一下 这篇文章,作者是大名鼎鼎的乔恩·斯基特 (Jon Skeet)。
另请查看此答案的最后部分,其中详细介绍了哪些内容应该使用
易失性
。I won't attempt to be an authority on this subject but I would highly recommend that you take a look at this article by the vaunted Jon Skeet.
Also take a look at the final part of this answer which details what
volatile
should be used for.是的,您可以通过使用易失性变量而不是锁来获得一些性能。
锁是一个完整的内存屏障,它可以为您提供与易失性变量以及许多其他变量相同的特征。正如已经说过的,易失性只是确保在多线程场景中,如果一个 CPU 更改其缓存行中的值,其他 CPU 会立即看到该值,但根本不确保任何锁定语义。
问题是锁比 易失性 更强大,你应该尽可能使用易失性以避免不必要的锁。
Yes, you can gain some performance by using a volatile variable instead of a lock.
Lock is a full memory barrier which can give you the same characteristics of a volatile variable as well as many others. As has already been said volatile just ensures that in multi-threaded scenarios if a CPU changes a value in its cache line, the other CPUs sees the value immediately but do not ensure any locking semantic at all.
The thing is lock is a lot more powerful than volatile and you should use volatile when you can to avoid unnecessary locks.