我正在使用C#和.NEt 3.5.OptionA和OptionB有什么区别?
class MyClass { private object m_Locker = new object(); private Dicionarym_Hash = new Dictionary (); public void OptionA() { lock(m_Locker){ // Do something with the dictionary } } public void OptionB() { lock(m_Hash){ // Do something with the dictionary } } }
我开始涉足线程化(主要是为多线程应用程序创建缓存,不使用HttpCache类,因为它没有附加到网站上),我在很多例子中都看到了OptionA语法在线看,但我不明白在OptionB上做了什么,如果有的话.
选项B使用要保护的对象来创建关键部分.在某些情况下,这更清楚地传达了意图.如果一致使用,它保证一次只有受保护对象的一个关键部分处于活动状态:
lock (m_Hash) { // Across all threads, I can be in one and only one of these two blocks // Do something with the dictionary } lock (m_Hash) { // Across all threads, I can be in one and only one of these two blocks // Do something with the dictionary }
选项A限制较少.它使用辅助对象为要保护的对象创建关键部分.如果使用多个辅助对象,则一次可以为受保护对象激活多个关键部分.
private object m_LockerA = new object(); private object m_LockerB = new object(); lock (m_LockerA) { // It's possible this block is active in one thread // while the block below is active in another // Do something with the dictionary } lock (m_LockerB) { // It's possible this block is active in one thread // while the block above is active in another // Do something with the dictionary }
如果仅使用一个辅助对象,则选项A等同于选项B. 就阅读代码而言,选项B的意图更清晰.如果您要保护多个对象,则选项B实际上不是一个选项.
要明白,锁(m_Hash)也很重要不是防止其他代码使用散列.它只能阻止其他代码运行,它也使用m_Hash作为锁定对象.
使用选项A的一个原因是因为类可能具有您将在lock语句中使用的私有变量.使用一个对象可以更容易地锁定对所有对象的访问,而不是尝试使用更精细的粒度锁来锁定对所需成员的访问.如果你尝试使用更精细的方法,你可能需要在某些情况下采取多个锁,然后你需要确保你总是以相同的顺序采取它们以避免死锁.
使用选项A的另一个原因是因为有可能在您的课程之外可以访问对m_Hash的引用.也许您有一个提供对它的访问的公共属性,或者您可能将其声明为受保护的,派生类可以使用它.在任何一种情况下,一旦外部代码引用它,外部代码就可能将其用于锁定.这也开启了死锁的可能性,因为您无法控制或知道锁将被采用的顺序.
实际上,如果您正在使用其成员,则锁定对象并不是一个好主意.Jeffrey Richter在他的书"CLR via C#"中写道,无法保证您用于同步的一类对象不会lock(this)
在其实现中使用(这很有趣,但它是Microsoft推荐的同步方式......然后,他们发现这是一个错误),所以使用一个特殊的单独对象进行同步总是一个好主意.因此,正如您所看到的,OptionB不会为您提供死锁保证 - 安全性.因此,OptionA比OptionB更安全.