我刚刚发现了 Interlocked
类,现在我有一些基本问题。
根据我的理解,在多线程中操作数字变量时应该使用 Interlocked。如果该陈述为真,那么进行读取或只是对变量进行一般使用呢?
例如:
if ((iCount % 100) == 0)
我需要在那里使用 Interlocked
语句吗?
当我初始化变量时呢:
Int32 iCount = 0;
我需要确保在实现之前理解这一点。
最佳答案
这里有多种因素,但主要是波动性和原子性。在您的声明中:
if ((iCount % 100) == 0)
Do I need to use an Interlocked statement there?
我们首先需要问“什么是iCount
?”。如果它是long
/ulong
,那么它不能保证是原子的,所以你绝对需要某种保护(例如通过 Interlocked
)以避免获得“撕裂”值(在更新过程中读取它,给出一个它实际上从未存在过的幻像值 - 例如,从 00000000
到 FFFFFFFF
,您可以读取 0000FFFF
或 FFFF0000
)。如果它是一个int
,它会被保证是原子的。下一个问题是:我需要查看更新吗? CPU 内置了不同级别的缓存,看起来从字段中读取的代码可能最终实际上只是从本地寄存器或缓存中读取 - 而从不触及实际内存。如果这是一个风险,那么您可以通过使用 Interlocked
来减轻它,尽管在许多情况下使用 volatile
也可以防止这种情况。
讨论更新时会出现第三个更棘手的问题:您是否希望“最后编辑盲目获胜”?如果是这样,只需更新该值(大概使用 volatile
来允许读取) - 但是 - 如果两个线程正在编辑,则存在丢失更新的风险。例如,如果两个线程各自同时递增和递减,则最终值可能是 0
或 1
- 不一定是您想要的。 Intelocked
提供了通过更改检测进行更新的方法,以及执行递增/递减/添加等常见操作的辅助方法。
关于你的另一个问题:
What about when I'm initializing the variable:
Int32 iCount = 0;
字段初始化器仅在一个线程上执行,因此不需要额外的保护 - 这很好。
但是!线程很难。如果您完全不确定,请保持简单:使用 lock
。例如(假设您想要每个实例同步):
private int iCount = 0;
private readonly object syncLock = new object();
...
lock(syncLock) {
// code that reads or manipulates iCount
}
在许多情况下,这工作正常。
关于c# - 互锁 - 我什么时候使用它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16420242/