这是我之前提出的一个问题的解释.这是一个简单的线程问题,但我似乎无法理解.
如果我有共享代码:
private static object objSync = new object();
private int a = 0;
public void function()
{
lock(objSync)
a += 2;
lock(objSync)
a += 3;
Console.WriteLine(a.ToString());
a=0;
}
我不能期望最后的“ a”等于5,因为第一个线程获得的锁将“ a”设置为2,然后下一个线程可以在第一个线程能够将锁设置为“ 4”之前获得锁.加3,最后得到7.
据我了解,解决方案是在整个事情上加一个锁,然后您总是可以期望得到5.现在我的问题是,如果两个锁之间有一百万行代码,那该怎么办.我无法想象要锁定一百万行代码.您如何通过在大约一百万行和两行代码之间加一个锁来确保线程安全,但又不会导致性能下降?
编辑:
这是我为该问题编写的废话代码.实际应用是线路监控系统.有两个显示当前行的屏幕,一个显示给文员,另一个显示给公众.职员的屏幕通过串行端口接受“点击”,从而使行前进一格,然后通过notify事件更新公共屏幕(请参阅观察者设计模式).问题是,如果您向答题器发送垃圾邮件,它们将不会同步.我想象发生了什么事,就是第一个屏幕被添加到行号中,显示它,然后更新公共屏幕,但是在公共屏幕有机会显示数据库中的行号之前,业务员再次单击并且该行号消失了同步上面的“ a”代表我从数据库中检索到的值,而不仅仅是一个简单的int值.我在几个地方更改了值,我需要所有这些都自动发生.
解决方法:
这完全取决于您定义的“成功”.如果这是一个计数器,那可能仍然是正确的结果.如果只想按原样更新它,则在第一个锁中拍摄快照,然后与最终锁中的快照进行比较.在那种情况下,您可以用一些Interlocked.CompareExchange替换许多代码.同样在“计数器”方案中,Interlocked.Increment是您的朋友.
如果代码必须匹配,那么您有几个选择:
>如果比较失败,请再次运行整百万行;重复直到赢得比赛(通过匹配)
>如果比较失败,则引发异常
>*百万条线路;可能仍然是一百万行…
>考虑其他适合您情况的解决策略
在前两个中,您应该通过将任何相关数据置于中间状态来监视污染情况.
顺便说一句最终分配给0可能也应该是同一锁定策略的一部分.只有所有访问都尊重锁,锁才起作用.
但是只有您的情况可以告诉我们冲突中的“正确”行为是什么.