【问题标题】:Lock Sharing Between Classes类之间的锁共享
【发布时间】:2011-08-14 16:01:28
【问题描述】:

我正在尝试寻找在多个类之间共享锁定文件的最佳实践。在此之前,我将多个函数放在同一个类中,这样它们就可以共享一个互锁文件和一个生产者/消费者队列。代码比我想要的要长一些,我想把它们分成单独的类。当我这样做时,我无法共享锁定文件或添加/删除命令的队列。

我需要一个 UI 线程来接受来自用户的输入,然后将命令放入一个锁定的队列中,工作线程可以从中提取。我想将 UI 线程和工作函数放在不同的类中,以使我的代码井井有条。

对不起,如果这太含糊了。有没有办法做到这一点,不会破坏良好的设计技术?

【问题讨论】:

    标签: c# multithreading locking


    【解决方案1】:

    如果锁在多个类之间共享,并且“所有者”不易识别,则将这些锁放入共享的类中。

    public class MyLocks { ... all your locks ... }
    

    然后,当您初始化使用锁的类时,将它们传递给构造函数。或者,您可以让类自己实例化 MyLock,然后将其公开为您可以在后续构造中使用的属性。

    ...
    var a = new ClassWithLocks();
    var b = new ClassWithLocks(a.MyLocks);
    var b = new SomeOtherClassWithLocks(a.MyLocks);
    ...
    

    外卖是将锁放入自己的单元中。

    更新

    将多个锁放入自己的类的另一个好处是,您可以显式创建获取和释放锁的方法。例如:

    void PushLock(string myToken, LOCK_ENUM theLockIWant);
    void PopLock(string myToken, LOCK_ENUM theLockIWant);
    

    现在一个特定的类或操作可以请求锁,但是如果他们试图获取一个枚举数小于他们请求的锁的锁,你可以抛出一个异常。当您需要多个锁来执行操作时,这一点很重要,因为您可以确保锁被按顺序获取和释放,这是死锁最常见的罪魁祸首之一。

    【讨论】:

    • 这是我正在考虑使用的,但读到以这种方式传递锁定文件并不是一个好的设计。我认为对于一个唯一被锁定的项目是工作排队,不过这不是什么大问题。
    • 如果两个类紧密耦合以至于它们知道彼此的锁,那么它们实际上是作为一个可测试的单元运行的。有一些技巧可以通过接口和嵌套类向公众隐藏锁的实现,但这可能是矫枉过正。在实践中,我通过创建一个提交到队列的 WorkItem 来最小化所需的锁数量。队列由单个线程消耗,该线程在轮到提交者时调用提交者,并且完全避免了回调函数获取任何锁的需要。当然,这一切都取决于你在做什么。
    【解决方案2】:

    您可以使用 System.Collection.Concurrent 命名空间中的线程安全 ConcurrentQueue,并在您的 UI 线程和工作线程之间共享此队列,如下所示:

    ConcurrentQueue<T> workItems = new ConcurrentQueue<T>();
    
    UIThreadClass uiThread = new UIThreadClass(workItems);
    
    WorkerThreadClass workerThread = new WorkerThread(workItems);
    
    uiThread.Run();
    
    workerThread.Run();
    

    在您的工作线程类中,您可以定期检查工作项队列 使用 TryPeek() 方法获取新项目。有关详细说明 ConcurrentQueue 参考MSDN

    希望,这会有所帮助。

    【讨论】:

      【解决方案3】:

      什么是“锁定文件”?你在使用 FileStream Lock / Unlock 方法吗?如果是这样,您可能会考虑是否真的需要它们。

      回到锁定:我认为在大多数情况下(以及您的情况)应该使用简单的共享ReaderWriterLock(Slim)。 Michael 概述了基本想法 - 您应该在此基础上添加一个 singleton - 它会大大简化您的项目和生活(无需传递实例,更易于调试)。

      小心那些线程,死锁不好玩!

      PS:这可能很明显(对某些人来说),但锁只在处理多个线程时才有效。

      【讨论】:

      • 对不起,我的意思是一个锁变量,比如只读对象 workLock = new object();
      • 谢谢。看到你对死锁的评论让我想起了一个集中的类可以让人们在解决锁问题时更加慎重——特别是允许一个人按顺序获取锁并只按该顺序释放。
      猜你喜欢
      • 2014-10-22
      • 2020-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-04
      • 1970-01-01
      • 2012-12-06
      相关资源
      最近更新 更多