【问题标题】:C# mutex through reference通过引用的 C# 互斥锁
【发布时间】:2014-01-21 11:39:33
【问题描述】:

我有一个相当简单的例子,两个线程与相同的数据结构交互。线程托管在它们自己负责的类中。假设这些是 Alfons 类和 Belzebub 类:

class Alfons {
    public Mutex listMutex = new Mutex();

    private void ProcessListInfo()
    {
        listMutex.WaitOne();

        //
        // ... Process multi-access list stuff ...
        //

        listMutex.ReleaseMutex();
    }
}

class Belzebub {
    private Alfons mCachedAlfonsReference;

    private void ProcessListInfoDifferently()
    {
        mCachedAlfonsReference.listMutex.WaitOne();

        //
        // ... Process multi-access list stuff in a different fashion ...
        //

        mCachedAlfonsReference.listMutex.ReleaseMutex();
    }
}

我的问题是,像这样引用 Mutex 是否会产生并发问题,或者是否建议这样做。有没有更好的方法来做到这一点,例如,我是否应该缓存互斥体引用而不是通过引用访问它。

【问题讨论】:

  • 是的!非常感谢!事实上,我想将你们俩都标记为答案(dcastro 和 acarlon)。多亏了这些,我最终对我的数据类型进行了一些重组:)
  • 很高兴能提供帮助 - dcastro 是第一个,非常公平。

标签: c# concurrency mutex


【解决方案1】:

不会有并发问题 - 应该共享互斥体。根据Mutex MSDN docs

这种类型是线程安全的。

但是,我想说数据结构本身应该同步来自不同线程的访问。如果数据结构不支持此功能(例如,使用SyncRoot),请将其封装并添加该功能。

出于好奇:您使用的是哪种数据结构?您可以考虑使用System.Collections.Concurrent 集合之一来实现无锁/细粒度锁定解决方案。另外,在您的场景中使用lock keyword 会不会更简单、更不容易出错?

【讨论】:

    【解决方案2】:

    一般来说,由于锁定可能很棘手并且死锁会停止所有乐趣,因此我尝试减少与互斥锁有关的代码,而不是到处传递它。否则,找出导致锁定的路径可能会令人头疼。

    最好将资源和线程关键操作封装在一个类中,然后:

    Lock( this )
    {
    }
    

    或者看看是否有 dcastro 建议的线程安全版本。

    除此之外,要非常小心 WaitOne()ReleaseMutex() 之间没有返回(抛出等),否则其他线程将被无限期锁定 - lock 或带有 ReleaseMutexfinally 是在这方面更安全。正如卡斯特罗在 cmets 中指出的那样,它可能是另一个引发异常的库。

    最后,我假设它是在 ProcessListInfo() 和 ProcessListInfoDifferently() 中受保护的同一资源。如果这是两个受保护的不同资源,那么您扩大了不必要的线程争用的可能性。

    【讨论】:

    • +1,互斥锁应该在finally 块内释放,以防止可能的异常。即使您自己的代码没有故意抛出异常,请注意ThreadAbortException 之类的异常仍然可能发生。
    【解决方案3】:

    我看不出缓存互斥体引用会有什么不同,无论哪种方式你仍然通过引用访问同一个对象,如果你不这样做,那么它就会破坏互斥体的意义。

    【讨论】:

      猜你喜欢
      • 2016-12-27
      • 2022-07-31
      • 1970-01-01
      • 2018-05-23
      • 1970-01-01
      • 2011-08-10
      • 1970-01-01
      • 1970-01-01
      • 2015-09-10
      相关资源
      最近更新 更多