互锁 - 我什么时候使用它?

时间:2013-05-07 13:24:59

标签: c#

我刚刚发现Interlocked课程,现在我有一些基本问题。

根据我的理解,我应该在多线程操作数字变量时使用Interlocked。如果该陈述是真的,那么做什么读或只是一般使用变量呢?

例如:

if ((iCount % 100) == 0)

我是否需要在那里使用Interlocked声明?

当我初始化变量时:

Int32 iCount = 0;

我需要确保在理解之前理解这一点。

3 个答案:

答案 0 :(得分:4)

这里有各种因素,但主要是波动率原子性。在你的陈述中:

if ((iCount % 100) == 0)
     

我是否需要在那里使用Interlocked语句?

我们首先要问“什么是iCount?”。如果是long / ulong,则不能保证 atomic ,因此您绝对需要某种保护(例如通过Interlocked)以避免获得“撕裂”的价值(通过更新中途阅读它,提供从未实际存在的幻像值 - 例如,从00000000更改为FFFFFFFF你可以阅读0000FFFFFFFF0000)。如果它是int,它将保证原子。接下来的问题是:我需要查看更新吗? CPU内置了各种级别的缓存,出现以从字段中读取的代码最终 只能从本地寄存器或缓存中读取 - 并且从不接触实际记忆。如果这是一个风险,那么您可以使用Interlocked来缓解这种风险,尽管在许多情况下使用volatile也可以防范此问题。

在讨论更新时会出现第三个问题:你想要“最后编辑盲目获胜”吗?如果是这样,只需更新值(可能使用volatile来允许读取) - 但是 - 如果两个线程正在编辑,则存在丢失更新的风险。例如,如果两个线程同时递增和递减,则最终值可以是01 - 不一定是您想要的。 Intelocked提供了使用更改检测进行更新的方法,以及帮助方法来执行常规操作,如递增/递减/添加/等。

回答你的另一个问题:

  

当我初始化变量时:

Int32 iCount = 0;

字段初始化程序仅在一个线程上执行,因此不需要额外的保护 - 这很好。


然而!线程很难。如果您完全不确定,请保持简单:使用lock。例如(假设您希望每个实例同步):

private int iCount = 0;
private readonly object syncLock = new object();
...
lock(syncLock) {
    // code that reads or manipulates iCount
}

在许多情况下,这种方法很好。

答案 1 :(得分:1)

在共享,可变状态下进行多线程处理时,需要进行同步。您需要使用InterlockedInterlocked适用于高级用户。我建议你使用lock C#语句,只使用Interlocked来表示简单的情况(增加共享计数器)或性能危急情况。

Interlocked一次只能用于访问单个变量,并且只支持非常原始的操作。您将很难与Interlocked同步多个变量。

在您的示例中,没有人可以判断您是否需要同步,因为线程安全是整个程序的属性,而不是单个语句或函数的属性。您需要将所有在共享状态下运行的代码视为一个整体。

答案 2 :(得分:0)

我想补充其他答案,微软还额外引入了ImmutableInterlocked类。

此类用于处理不可变集合。该类具有一组用于使用Compare-And-Swap模式更新不可变集合的函数。

您可以在System.Collections.Immutable命名空间中找到它。

https://msdn.microsoft.com/en-us/library/system.collections.immutable.immutableinterlocked(v=vs.111).aspx