何时在线程安全锁定代码中使用’volatile’或’Thread.MemoryBarrier()’? (C#)

我什么时候应该使用volatile / Thread.MemoryBarrier()来保证线程安全?

如果要跨线程访问变量而不锁定,则使用volatile / Thread.MemoryBarrier()

primefaces变量(例如int总是一次读写整个变量。 这意味着在另一个线程更改之前,您将永远不会获得一半的值,而在更改之后,另一半则不会。 因此,您可以安全地在不同的线程中读取和写入值,而无需同步。

但是,编译器可能会优化掉一些读取和写入,而使用volatile关键字会阻止这些读取和写入。 例如,如果您有一个这样的循环:

 sum = 0; foreach (int value in list) { sum += value; } 

编译器实际上可以在处理器寄存器中进行计算,并且仅在循环之后将值写入sum变量。 如果将sum变量设置为volatile ,则编译器将生成用于为每个更改读取和写入变量的代码,以使其在整个循环中的值是最新的。

怎么了?

 private static readonly object syncObj = new object(); private static int counter; public static int NextValue() { lock (syncObj) { return counter++; } } 

这会为您完成所有必要的锁定,内存障碍等。 与基于volatileThread.MemoryBarrier()任何自定义同步代码相比,它的理解和可读性更强。


编辑

我想不出我使用volatileThread.MemoryBarrier()的场景。 例如

 private static volatile int counter; public static int NextValue() { return counter++; } 

等同于上面的代码,并且不是线程安全的( volatile不会使++神奇地成为线程安全的)。

在这种情况下:

 private static volatile bool done; void Thread1() { while (!done) { // do work } } void Thread2() { // do work done = true; } 

(应该工作)我会使用ManualResetEvent来表示Thread2何时完成。

基本上,如果您使用任何其他类型的同步来使您的代码线程安全,那么您不需要。

大多数锁定机制(包括锁定)自动暗示内存屏障,以便多个处理器可以获得正确的信息。

Volatile和MemoryBarrier主要用于无锁情况,您试图避免锁定的性能损失。

编辑:你应该阅读Joe Duffy关于CLR 2.0内存模型的这篇文章 ,它澄清了很多东西(如果你真的很感兴趣,你应该阅读来自Joe Duffie的所有文章,他是大多数并行的专家。 。净)

顾名思义,保证将缓存值刷新到内存,以便所有线程都看到相同的值。 例如,如果我有一个整数,其最新写入保存在缓存中,其他线程可能看不到。 他们甚至可以看到他们的整数缓存副本。 将变量标记为volatile会使其直接从内存中读取。

Sriwantha Sri Aravinda Attanayake