我刚刚发现Interlocked
课程,现在我有一些基本问题。
根据我的理解,我应该在多线程操作数字变量时使用Interlocked。如果该陈述是真的,那么做什么读或只是一般使用变量呢?
例如:
if ((iCount % 100) == 0)
我是否需要在那里使用Interlocked
声明?
当我初始化变量时:
Int32 iCount = 0;
我需要确保在理解之前理解这一点。
答案 0 :(得分:4)
这里有各种因素,但主要是波动率和原子性。在你的陈述中:
if ((iCount % 100) == 0)
我是否需要在那里使用Interlocked语句?
我们首先要问“什么是iCount
?”。如果是long
/ ulong
,则不能保证 atomic ,因此您绝对需要某种保护(例如通过Interlocked
)以避免获得“撕裂”的价值(通过更新中途阅读它,提供从未实际存在的幻像值 - 例如,从00000000
更改为FFFFFFFF
你可以阅读0000FFFF
或FFFF0000
)。如果它是int
,它将保证原子。接下来的问题是:我需要查看更新吗? CPU内置了各种级别的缓存,出现以从字段中读取的代码最终 只能从本地寄存器或缓存中读取 - 并且从不接触实际记忆。如果这是一个风险,那么您可以使用Interlocked
来缓解这种风险,尽管在许多情况下使用volatile
也可以防范此问题。
在讨论更新时会出现第三个问题:你想要“最后编辑盲目获胜”吗?如果是这样,只需更新值(可能使用volatile
来允许读取) - 但是 - 如果两个线程正在编辑,则存在丢失更新的风险。例如,如果两个线程同时递增和递减,则最终值可以是0
或1
- 不一定是您想要的。 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)
在共享,可变状态下进行多线程处理时,需要进行同步。您需要使用Interlocked
。 Interlocked
适用于高级用户。我建议你使用lock
C#语句,只使用Interlocked
来表示简单的情况(增加共享计数器)或性能危急情况。
Interlocked
一次只能用于访问单个变量,并且只支持非常原始的操作。您将很难与Interlocked
同步多个变量。
在您的示例中,没有人可以判断您是否需要同步,因为线程安全是整个程序的属性,而不是单个语句或函数的属性。您需要将所有在共享状态下运行的代码视为一个整体。
答案 2 :(得分:0)
我想补充其他答案,微软还额外引入了ImmutableInterlocked类。
此类用于处理不可变集合。该类具有一组用于使用Compare-And-Swap模式更新不可变集合的函数。
您可以在System.Collections.Immutable命名空间中找到它。