从Reference Source我们可以看到上述方法实现如下:
public static void Enter(Object obj, ref bool lockTaken)
{
if (lockTaken)
ThrowLockTakenException();
ReliableEnter(obj, ref lockTaken);
Contract.Assert(lockTaken);
}
我有一个问题是' if'陈述 - 我理解它的重要性,没有必要解释它。我相信这个陈述也引入了一个非常微妙的问题。
请考虑以下情形: 一个线程调用方法并计算if语句,此时发生上下文切换,另一个调用方法,成功获取锁。
这是一个可行的场景,表明锁定获取的顺序不一定与方法调用的顺序相同。
虽然在某些情况下它可能不会有所作为,但在其他情况下它可能至关重要,所以我的问题是:
1)我是否遗漏了某些内容,或者Monitor类不适合在不可接受的情况下使用?
2)ReliableEnter是否有可能遭遇类似的情况?
3)是否存在同步机制,确保方法调用的顺序与锁获取的顺序相同?
答案 0 :(得分:12)
一个线程调用方法并计算if语句,此时发生上下文切换,另一个调用方法,成功获取锁。
这完全有可能。
或者,可能没有上下文切换但这仍然会发生。两个线程都通过" if"并且进入ReliableEnter,两者都没有上下文切换,一个获胜。你能想到发生这种情况的情景吗?
这是一个可行的场景,表明锁定获取的顺序不一定与方法调用的顺序相同。
记住三位裁判的故事。
三位裁判正在吃午饭。第一个说"当我看到它们时,我称它们为#34;。第二个说"我称他们为"。第三个说"除非我打电话给他们,否则他们什么都没有。"
第一位裁判认为观察是不完美的,人们可能不同意球场是球还是球。第二个人认为,有一个一致的物理世界,他们有准确的信息;可以客观地确定球是球还是球。第三个人认为,无论世界是否一致和可知,棒球的规则都说罢工是裁判员称之为罢工的任何东西。
你是第二位裁判。你认为实际上存在这样的事情"方法调用发生的顺序"在一个多线程的世界里,有一种方法可以了解它。但实际上这个世界更像是第一个裁判员:每个人都可以看到一个不同的世界并且不同意它。锁更像是第三个裁判:锁是对无序世界强加排序的东西。这些方法的命令是什么顺序? 锁定并找出。
放弃了在多线程世界中事情发生的一致顺序的神话。 没有这样一致的订单。每个处理器都可以在内存模型约束中尽可能多地重新排序代码。每个线程都可以看到不同的读写顺序。
每个线程都同意的是锁定的顺序,因此这是明智的选择"顺序"在哪种方法调用。
那么,锁可以以与方法调用不同的顺序发生吗?第一位裁判说,#34;没有人能确切知道"。第二个说"是"。第三个说"在锁定之前没有任何订单"。
我同意第三位裁判员的意见。锁可以采用与调用方法不同的顺序吗?由于强制执行该命令的唯一方法是采取锁定,因此这不是一个明智的问题。
1)我是否遗漏了某些内容,或者Monitor类不适合在不可接受的情况下使用?
这是错误的看法。
如果我们继续相信存在一个调用发生顺序的虚构,并且你有一个程序依赖于完全神话顺序中锁定的正确性,则该程序有一个错误。锁定不采取"呼叫发生的顺序",故事结束,如果你依赖于此,那么你依赖于no所做的保证。一个并经常违反。
2)ReliableEnter是否有可能遭遇类似的情况?
我不明白这个问题。您的意思是,如果我们通过拨打Enter
来取代对ReliableEnter
的每次通话,我们是否还会遇到同样的问题?是的,绝对。
3)是否存在同步机制,确保方法调用的顺序与锁获取的顺序相同?
没有这样的顺序独立于锁,所以没有。
我有一个问题是' if'陈述 - 我理解它的重要性,没有必要解释它。我相信这个陈述也引入了一个非常微妙的问题。
你的信念是对的。这个问题是由于没有"方法调用发生的顺序和#34;在一个多线程的世界里。 "如果"没有任何关系。
此外,即使在我们能从锁中提取订购信息的世界中,锁也不能保证公平。如果你有10个线程都在等待一个锁定,那么C#语言就没有要求那个已经等待最长的线程"或者"先叫#34; - 无论这意味着什么 - 是接下来访问监视器的人。操作系统具有广泛的自由度,可以根据需要调度线程,并且无限期地将线程饿死是有权利的。
现在,我上面所说的有很多半真半假。世界的实际状况非常混乱。如果你想知道真相那么你应该阅读关于多线程程序中副作用的排序的C#规范部分,它描述了保证观察到特定顺序的事件:锁,线程的创建,某些类型的读写,异常和构造函数调用。在某些情况下,订购保证非常薄弱。
正如我一直这样做的时候,我建议你阅读我关于如何在没有锁定的世界中进行重新排序的文章。看看你是否可以解决我在第二部分中提出的难题。
http://blog.coverity.com/2014/03/12/can-skip-lock-reading-integer/ http://blog.coverity.com/2014/03/26/reordering-optimizations/
答案 1 :(得分:0)
我不认为你所描述的是一个实际问题。 if语句与锁的状态无关。它仅用作输入验证,以确保第二个参数的值为false。
想象一下if语句不在那里。例如,在将返回地址压入堆栈之后和执行跳转指令之前,上下文切换仍然可能发生。
锁用于防止程序进入不一致状态。但是,如果关键部分的结构正确,锁定获取的顺序并不重要。在您描述的示例中,程序将继续,就好像第二个线程已获得锁定,第一个线程将在lockTaken参数中具有false
。