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

时间:2011-05-24 14:47:23

标签: c# multithreading locking

好吧,我已经使用了很多锁,但我之前从未有过这种情况。我有两个不同的类,包含用于修改相同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)由不同的线程调用。

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

5 个答案:

答案 0 :(得分:16)

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

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

现在UseSQLKatana和UseSQLCutlass调用ImplementationDetail.DoDatabaseQuery。

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

答案 1 :(得分:8)

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

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

答案 2 :(得分:2)

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

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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

为什么lock对公共对象不好?

我们的想法是,在维护lock时锁定对象会限制访问 - 这意味着无法访问其成员,并且其他来源可能无法识别lock并尝试利用实例,甚至尝试自己获取lock,从而导致问题。

出于这个原因,请使用专用对象实例锁定。

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

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