【问题标题】:Why Locking On a Public Object is a Bad Idea为什么锁定公共对象是个坏主意
【发布时间】:2011-05-24 14:47:23
【问题描述】:

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

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

【问题讨论】:

  • 我猜 db.TableAwesom 是一个公共表。您能否创建一个访问该表的公共方法,并在其中使用您的私有锁?

标签: c# multithreading locking


【解决方案1】:

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

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

现在 UseSQLKatana 和 UseSQLCutlass 调用 ImplementationDetail.DoDatabaseQuery。

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

【讨论】:

  • 我只是建议使用第三类方法,但我的打字速度没有那么快。 :P
  • 谢谢,埃里克,这些想法很好。让我们不要为了遵守规则而遵守规则。 =)
  • 我认为,如果这个想法只是为了让调试死锁问题变得更容易,那么公共互斥锁可能会有所帮助,但首先导致问题的可能性并不小而不是公共锁对象 - 您仍然可以对其进行其他代码锁定,从而导致问题。我看到的唯一解决方案是将访问资源的实例减少到一个方法(或至少一个类)并在那里锁定它;在那一点上是否使用互斥锁或对象似乎无关紧要。谢谢大家!!!
【解决方案2】:

锁定公共对象是不好的做法的原因是您永远无法确定谁 ELSE 锁定了该对象。尽管不太可能,但有一天其他人可以决定他们想要获取您的锁定对象,并执行一些最终调用您的代码的过程,您锁定同一个锁定对象,现在您有一个不可能解决的死锁。 (使用 'this' 也是同样的问题)。

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

【讨论】:

【解决方案3】:

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

【讨论】:

  • 使用公共互斥体锁定比锁定公共对象更好(或更差)如何?
  • @Eric:我也建议过Mutex,我认为因为我们可以“等待”它让我们能够控制流量而不是可能彻底中断,或者我们可以使用ReaderWriterLockSlimTryEnter和某某-最终允许访问“状态”,我猜这会有所帮助-我认为您认为不是吗?只是问,因为如果是这样,我会删除我的错误答案。
  • @Mr.失望:让我澄清一下;我无意批评马可的回答;而是一个诚实的问题。阅读此答案的人可能会感到困惑:如果您可以使用锁或互斥锁,那么它们各自的优缺点是什么?
  • @Eric,@Mr.失望:互斥锁用于同步并发线程,所以在我看来这是使用互斥锁的“自然环境”。但这是我的意见,我可能是错的,所以如果你教我一个更好的方法,我说谢谢! ! :)
  • @Eric:我想决定性因素将取决于哪一种最能帮助预防问题(或在出现人为错误时缓解)。
【解决方案4】:

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

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

这个想法是锁定一个对象会限制访问,而 lock 被维护 - 这意味着它的任何成员都不能被访问,并且其他来源可能不知道 lock 并尝试使用该实例,甚至试图自己获取lock,从而导致问题。

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

如何锁定这些方法,以免它们同时运行?

你可以考虑Mutex类;创建一个“全局”互斥锁将允许您的类在了解整个应用程序中的锁状态的基础上进行操作。或者,您可以使用共享的ReaderWriterLockSlim 实例,但我真的不建议跨类共享它。

【讨论】:

  • 好电话,这确实是两个问题 - 感谢您对这两个问题的意见!
【解决方案5】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-31
    • 1970-01-01
    • 2010-10-07
    • 2021-08-23
    • 1970-01-01
    • 2011-11-29
    相关资源
    最近更新 更多