[英]interlocked - when do I use it?
我刚刚了解了Interlocked
类,现在有一些基本问题。
据我了解,多线程处理数字变量时应该使用互锁。 如果该说法是正确的,那么如何进行读取或只是常规使用变量呢?
例如:
if ((iCount % 100) == 0)
我是否需要在此处使用“ Interlocked
语句?
当我初始化变量时该怎么办:
Int32 iCount = 0;
在实施之前,我需要确保我理解这一点。
这里有多种因素,但主要是波动性和原子性 。 在您的陈述中:
if ((iCount % 100) == 0)
我是否需要在此处使用“互锁”语句?
我们首先需要问“什么是iCount
?”。 如果它是long
/ ulong
,那么就不能保证它是原子的 ,因此,您绝对需要某种保护(例如通过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
}
在许多情况下,这可以正常工作。
在共享的可变状态上进行多线程处理时,您需要同步。 您不需要使用Interlocked
。 Interlocked
适用于高级用户。 我建议您使用lock
C#语句,并且仅在发生简单情况(增加共享计数器)或对性能要求较高的情况下使用Interlocked
。
Interlocked
只能一次访问单个变量,并且仅支持非常原始的操作。 使用Interlocked
同步多个变量将非常困难。
在您的示例中,没有人可以告诉您是否需要同步,因为线程安全性是整个程序的属性,而不是单个语句或函数的属性。 您需要将所有在共享状态下运行的代码视为一个整体。
我想补充其他答案,微软另外引入了ImmutableInterlocked类。
此类用于处理不可变集合。 该类具有一组用于使用Compare-And-Swap模式更新不可变集合的函数。
您可以在System.Collections.Immutable命名空间中找到它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.