【发布时间】:2011-09-01 00:00:04
【问题描述】:
可能重复:
Threads synchronization. How exactly lock makes access to memory 'correct'?
这个问题的灵感来自this one.
我们得到了以下测试类
class Test
{
private static object ms_Lock=new object();
private static int ms_Sum = 0;
public static void Main ()
{
Parallel.Invoke(HalfJob, HalfJob);
Console.WriteLine(ms_Sum);
Console.ReadLine();
}
private static void HalfJob()
{
for (int i = 0; i < 50000000; i++) {
lock(ms_Lock) { }// empty lock
ms_Sum += 1;
}
}
}
实际结果非常接近预期值 100 000 000(50 000 000 x 2,因为 2 个循环同时运行),差异约为 600 - 200(我的机器上的错误约为 0.0004%,这非常低的)。没有其他同步方式可以提供这种近似方式(它要么是更大的错误,要么是 100% 正确)
我们目前了解到,这种精确度是因为程序运行方式如下:
时间从左到右运行,2个线程用两行表示。
在哪里
黑框代表获取、持有和释放的过程
lock plus 表示加法操作(schema 表示 scale on 我的电脑,加锁的时间大约是加锁时间的 20 倍)
- 白框表示由尝试获取锁组成的周期, 并进一步等待它可用
锁还提供完整的内存围栏。
所以现在的问题是:如果上面的模式代表正在发生的事情,那么大错误的原因是什么(现在它的大原因模式看起来像非常强的同步模式)?我们可以理解边界上 1-10 之间的差异,但它显然不是错误的唯一原因?我们看不到何时会同时写入 ms_Sum,从而导致错误。
编辑:很多人喜欢草草下结论。我知道同步是什么,如果我们需要正确的结果,上述构造并不是真正的或接近同步线程的好方法。对海报有信心,或者先阅读链接的答案。我不需要同步 2 个线程以并行执行加法的方法,与 any 可能和 近似 替代同步构造相比,我正在探索这种奢侈而高效的方法(它确实在一定程度上同步,所以它的 不是毫无意义就像建议的那样)
【问题讨论】:
-
首先它不是重复的,其次该问题还没有确定的答案,并且有一个标记的答案,可以停止可能的讨论以获取实际原因
-
如果您阅读了接受的答案,它会告诉您为什么此代码有机会产生正确的结果但不能保证正确的结果......它还会告诉您正确的代码需要什么以及为什么它会产生正确的结果...
-
使用
Interlocked.Increment(ref ms_Sum);并同时解除锁定可能会解决您的问题。 -
@vcsjones 就像我说的,你建议采用 100% 同步方法,我在问这个小错误的来源是什么。
-
Nobody explained the residual error. It is caused by the Windows thread scheduler
标签: c# .net multithreading locking