何时使用“易失性”?或“Thread.MemoryBarrier()”在线程安全锁定代码中? (C#)
我什么时候应该使用 volatile/Thread.MemoryBarrier() 来保证线程安全?
When should I use volatile/Thread.MemoryBarrier() for thread safety?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
当您想要跨线程访问变量而不加锁时,可以使用
volatile
/Thread.MemoryBarrier()
。原子变量(例如
int
)总是一次读取和写入整个变量。这意味着您永远不会在另一个线程更改该值之前获得该值的一半,也不会在该值更改后获得另一半。因此,您可以安全地在不同线程中读取和写入该值,而无需同步。但是,编译器可能会优化一些读取和写入操作,您可以使用
volatile
关键字来阻止这些操作。例如,如果您有这样的循环:编译器实际上可能在处理器寄存器中进行计算,并且仅在循环后将值写入
sum
变量。如果将sum
变量设为易失性
,编译器将生成针对每次更改读取和写入该变量的代码,以便其值在整个循环中保持最新。You use
volatile
/Thread.MemoryBarrier()
when you want to access a variable across threads without locking.Variables that are atomic, like an
int
for example, are always read and written whole at once. That means that you will never get half of the value before another thread changes it and the other half after it has changed. Because of that you can safely read and write the value in different threads without syncronising.However, the compiler may optimize away some reads and writes, which you prevent with the
volatile
keyword. If you for example have a loop like this:The compiler may actually do the calculations in a processor register and only write the value to the
sum
variable after the loop. If you make thesum
variablevolatile
, the compiler will generate code that reads and writes the variable for every change, so that it's value is up to date throughout the loop.有什么问题吗
?
这会为您完成所有必要的锁定、内存屏障等。它比任何基于
volatile
和Thread.MemoryBarrier()
的自定义同步代码更易于理解且更具可读性。编辑
我想不出使用
易失性
或Thread.MemoryBarrier()
的场景。例如,不等价于上面的代码,并且不线程安全(
易失性
不会使++
神奇地变成线程安全的)。在这样的情况下:(
应该有效)我会使用 ManualResetEvent 在 Thread2 完成时发出信号。
What's wrong with
?
This does all necessary locking, memory barriers, etc. for you. It's well understood and more readable than any custom synchronization code based on
volatile
andThread.MemoryBarrier()
.EDIT
I can't think of a scenario in which I'd use
volatile
orThread.MemoryBarrier()
. For exampleis not equivalent to the code above and is not thread-safe (
volatile
doesn't make++
magically become thread-safe).In a case like this:
(which should work) I'd use a ManualResetEvent to signal when Thread2 is done.
基本上,如果您使用任何其他类型的同步来使代码线程安全,那么您就不需要这样做。
大多数锁机制(包括锁)自动暗示内存屏障,以便多个处理器可以获得正确的信息。
Volatile 和 MemoryBarrier 主要用于无锁场景,您试图避免锁定的性能损失。
编辑:您应该阅读这篇文章< /a> Joe Duffy 撰写的关于 CLR 2.0 内存模型的文章,它澄清了很多事情(如果您真的感兴趣,您应该阅读 Joe Duffie 的所有文章,他是 .NET 并行性方面最专家的人)
Basically if you're using any other kind of synchronization to make your code threadsafe then you don't need to.
Most of the lock mechanisms (including lock) automatically imply a memory barrier so that multiple processor can get the correct information.
Volatile and MemoryBarrier are mostly used in lock free scenarios where you're trying to avoid the performance penalty of locking.
Edit: You should read this article by Joe Duffy about the CLR 2.0 memory model, it clarifies a lot of things (if you're really interested you should read ALL the article from Joe Duffie who is by large the most expert person in parallelism in .NET)
顾名思义,易失性保证将缓存值刷新到内存,以便所有线程看到相同的值。例如,如果我有一个整数,其最新写入保存在缓存中,其他线程可能看不到它。他们甚至可能会看到该整数的缓存副本。将变量标记为易失性使其可以直接从内存中读取。
斯里万塔·斯里·阿拉温达·阿塔纳亚克
As the name implies volatile guarantees that cache value are flushed to memory so that all the threads see the same value. For example, if I have an integer whose latest write is saved in the cache, other threads may not see that. They may even see their cache copy of that integer. Marking a variable as volatile makes it to be read directly from the memory.
Sriwantha Sri Aravinda Attanayake