为什么锁定公共对象是一个坏主意

好吧,我已经使用了很多锁,但我以前从未有过这种情况。 我有两个不同的类,包含用于修改相同的MSAccess数据库的代码:

public class DatabaseNinja { public void UseSQLKatana { //Code to execute queries against db.TableAwesome } } public class DatabasePirate { public void UseSQLCutlass { //Code to execute queries against db.TableAwesome } } 

这是一个问题,因为数据库的事务不能并行执行,并且这些方法(UseSQLKatana和UseSQLCutlass)由不同的线程调用。

在我的研究中,我发现使用公共对象作为锁定对象不好的做法,那么如何锁定这些方法以使它们不会串联运行? 答案只是让这些方法在同一个类中? (在我的实际代码中,这实际上并不那么简单)

好吧,首先,您可以创建第三个类:

 internal class ImplementationDetail { private static readonly object lockme = new object(); public static void DoDatabaseQuery(whatever) { lock(lockme) ReallyDoQuery(whatever); } } 

现在UseSQLKatana和UseSQLCutlass调用ImplementationDetail.DoDatabaseQuery。

其次,您可以决定不担心它,并锁定两种类型都可见的对象。 避免这种情况的主要原因是因为很难推断谁在锁定对象,并且难以防止恶意部分信任的恶意代码锁定对象。 如果您不关心任何一个缺点,那么您不必盲目遵循指南。

锁定公共对象的不良做法是,您永远无法确定ELSE是谁锁定该对象。 虽然不太可能,但有一天其他人可以决定他们想要获取你的锁对象,并做一些最终调用你的代码的进程,你锁定到同一个锁对象,现在你有一个不可能的死锁来搞清楚。 (使用’this’也是同样的问题)。

更好的方法是使用公共Mutex对象。 这些更重要,但调试问题要容易得多。

使用Mutex
您可以在主类中创建互斥锁,并在每个类的开头调用Wait方法(方法); 然后设置互斥锁,这样当调用另一个方法时,它将等待第一个类完成。
啊,记得发布退出这些方法的互斥量……

您可以使用公共LOCK对象作为锁定对象。 您只需要指定您正在创建的对象是一个仅用于锁定Ninja和Pirate类的Lock对象。

我在这里看到两个不同的问题:

为什么lock公共对象是个坏主意?

这个想法是锁定一个对象限制访问,同时保持lock – 这意味着它的所有成员都不能访问,而其他来源可能不知道lock并试图利用该实例,甚至试图获取一个lock本身因此导致问题。

因此,请使用专用对象实例锁定。

如何锁定这些方法以使它们不串联运行?

你可以考虑Mutex类; 创建“全局”互斥锁将允许您的类在知道整个应用程序中的锁状态的基础上运行。 或者,您可以使用共享的ReaderWriterLockSlim实例,但我不会真正推荐它的跨类共享。