为什么“lock(typeof(MyType))”有问题?
MSDN给出了关于C#中的锁关键字的以下警告:
通常,避免locking公共types或超出代码控制范围的实例。 常见的构造函数lock(this),lock(typeof(MyType))和lock(“myLock”)违反了这个指导原则:
* lock (this) is a problem if the instance can be accessed publicly. * lock (typeof (MyType)) is a problem if MyType is publicly accessible.
然而,它没有给出可靠的推理。 锁(这) 在这里解释。 我感兴趣的是lock(typeof(MyType))的情况。 什么危险呢?
谢谢。
这是很危险的,因为任何事情都可以采取这种locking,所以防止死锁情况是困难的或不可能的。
过去有一篇关于这个(“不要lockingtypes的对象!”一个博士GUI文章)的文章与Rico Mariani的一些评论。 显然这篇文章不再是直接可用的,但是有“镜子”浮动,包括http://bytes.com/topic/c-sharp/answers/249277-dont-lock-type-objects 。
这是一个摘录:
这里的基本问题是,你不拥有types对象,你不知道还有谁可以访问它。 一般来说,依靠locking一个你没有创build的对象并且不知道还有谁可能访问是一个非常糟糕的主意。 这样做会导致死锁。 最安全的方法是只locking私人对象。
可是等等; 比这更糟糕 事实certificate,有时在.NET运行时的当前版本中,types对象有时在应用程序域(但不跨进程)共享。 (这通常是可以的,因为它们是不可变的)。这意味着即使在不同的应用程序域(但在相同的进程中),也可以运行另一个应用程序,通过locking要locking的types对象来locking应用程序并永远不会释放它。 而且访问这个types的对象也很容易,因为这个对象有一个名字 – types的完全限定名称! 请记住,锁/ SyncLock块(这是一个礼貌的词挂起),直到它可以获得一个锁。 显然,真的很不好,依靠一个锁,其他程序或组件可以locking并导致死锁。
这与lock(this)
问题相同 – 您locking了其他代码可以访问的引用,所以也可以locking它。
如果你在同一个引用上有两个不相关的代码块,而不打算相互排斥,那么在最好的情况下,由于缺乏并发性,你可能会失去一些性能 – 最坏的情况是你可能会引入一个死锁。
因为typeof (MyType)
(它是一个types为Type
的对象)的结果是可以被广泛访问的,而其他线程可以locking在同一个对象上,并且无限地保存该锁。 然后,MyType的内部逻辑已经有效地控制了它的同步逻辑。 这可能不是一个真正的问题,如果这是有意的,但防御/怀疑编码应该是你的工作方式 。
因为一个锁的目标是只build立一个地方来存储锁布尔(我是否locking)其他线程看… –
一个常见的错误认为,锁的目标实际上是被locking的,这只是错误的……什么是“locking”,除非在方法中可以以不安全的方式访问某些共享内存,代码来查看这个锁,直到它被释放后才继续……使用Type对象作为锁目标是错误的,因为整个解决scheme进程空间中的任何地方的代码片断都可以访问该types对象,并更改同步块锁布尔被存储在中。创build一个本地作用域对象允许你更好地保证只有那些可以访问或混淆你的“风险”共享内存的线程和方法也可以访问和/或修改这个锁。
在主题“pipe理线程最佳实践”中还提到了文档。 https://msdn.microsoft.com/en-us/library/1c9txz50(v=vs.110).aspx
它说;
不要使用types作为锁对象。 也就是说,避免在Visual Basic中使用C#或SyncLock(GetType(X))中的lock(typeof(X)),或使用带有Type对象的Monitor.Enter。 对于给定types,每个应用程序域只有一个System.Type实例。 如果您locking的types是公共的,您自己以外的代码可以locking它,导致死锁 。 有关其他问题,请参阅可靠性 最佳实践 。
locking实例时要小心,例如C#中的lock(this)或Visual Basic中的SyncLock(Me)。 如果应用程序中的其他代码(该types外部的代码会locking对象) 可能 会发生 死锁 。