Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/324.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
何时使用';挥发性';或';Thread.MemoryBarrier()和#x27;在线程安全锁定代码中?(C#)_C#_.net_Multithreading_Volatile - Fatal编程技术网

何时使用';挥发性';或';Thread.MemoryBarrier()和#x27;在线程安全锁定代码中?(C#)

何时使用';挥发性';或';Thread.MemoryBarrier()和#x27;在线程安全锁定代码中?(C#),c#,.net,multithreading,volatile,C#,.net,Multithreading,Volatile,什么时候应该使用volatile/Thread.MemoryBarrier()实现线程安全?有什么问题 private static readonly object syncObj = new object(); private static int counter; public static int NextValue() { lock (syncObj) { return counter++; } } ? 这为您提供了所有必要的锁定、内存障碍等功

什么时候应该使用volatile/Thread.MemoryBarrier()实现线程安全?

有什么问题

private static readonly object syncObj = new object();
private static int counter;

public static int NextValue()
{
    lock (syncObj)
    {
        return counter++;
    }
}
?

这为您提供了所有必要的锁定、内存障碍等功能。它比任何基于
volatile
Thread.MemoryBarrier()
的自定义同步代码都易于理解和阅读


编辑

我想不出哪种场景会使用
volatile
Thread.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;
}
sum = 0;
foreach (int value in list) {
   sum += value;
}

(这应该可以工作)我会在Thread2完成时使用a来发出信号。

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

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

Volatile和MemoryBarrier主要用于无锁场景,在这些场景中,您试图避免锁定带来的性能损失


编辑:你应该阅读Joe Duffy关于CLR 2.0内存模型的文章,它澄清了很多事情(如果你真的感兴趣,你应该阅读Joe Duffie的所有文章,他大体上是.NET中最擅长并行的人)

你使用的
volatile
/
Thread.MemoryBarrier()
当您希望在不锁定的情况下跨线程访问变量时


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

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

private static volatile bool done;

void Thread1()
{
    while (!done)
    {
        // do work
    }
}

void Thread2()
{
    // do work
    done = true;
}
sum = 0;
foreach (int value in list) {
   sum += value;
}

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

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


Sriwantha Sri Aravinda Attanayake

您的代码没有“错误”。我试图掌握volatile&MemoryBarrier应用的环境。正如Jon Skeet在这里的回答:…net也有一个相当严格的内存模型,这样的读或写不能跟在另一个写之后。虽然ECMA规范有一个相当弱的内存模型,所以您可能需要注意这一点,请看,如果您只进行检索或赋值(说到第二个示例代码),因为它们是原子的。但是,是的,用途非常有限。我唯一能想到的地方是布尔菲尔德+1,但这是绝对清楚的。如果执行dtb所做的操作,则不需要volatile/Thread.MemoryBarrier。也有一些情况下,仅在成员上使用volatile是不够的。+1,但在哪些情况下,编译器会生成代码,为每次更改读取和写入变量,这很重要?这是在处理dtb时最需要的,如果没有一个线程得到与另一个线程不同的值,那么所有疯狂的事情都可能发生。好吧,这可能会使用内存障碍。当然,但我正在寻找一个真实的场景:)除了我回答中的最后一个例子之外,我想不出任何其他例子。“原子变量,例如int…”还有一个反例:设置长,x86计算机上的双精度或十进制变量不是线程安全的。编辑:参见底部的“螺纹安全”部分