【问题标题】:Correct pattern for multi-thread synchronization? (C#)多线程同步的正确模式? (C#)
【发布时间】:2009-11-08 18:41:52
【问题描述】:

我有两个线程引用同一个变量——UI 线程和一个计时器线程。因此,我已经在两个线程的 lock 语句中包装了对它的访问。定时器线程的访问具有优先级——如果它正在使用变量并且 UI 线程也想要访问,我希望 UI 线程的操作完成,但只有在定时器线程的操作完成之后。

但是,计时器线程可能委托给 UI 线程,因此 UI 线程需要有空闲来处理它。为了适应这种情况,我让 UI 线程启动第三个线程来处理其操作,以便它(第三个线程)可以等待计时器操作完成并且 UI 线程可以使用。锁定发生在第三个线程中。

我应该为这种同步使用什么正确的模式?

【问题讨论】:

  • 我们需要更多详细信息以获得不太通用的答案。两个线程都在读取和写入共享变量吗?计时器线程真的有必要在“委托”给 UI 线程时阻塞吗?一般来说,我#d避免引入第三个线程只是为了避免死锁——我宁愿保持复杂性小。

标签: c# synchronization multithreading


【解决方案1】:

一般建议是,关键部分中发生的任何事情都应尽可能简单。特别是你应该避免嵌套锁。嵌套锁可能是死锁的根源。

当应用于您在“计时器”线程中所做的事情时,您可能应该将关键部分与处理分开。定时器线程中的 IOW 只是从公共变量中检索数据,然后执行其余的处理,包括与锁外的 UI 线程的交互。

添加第三个线程不会让您的生活更轻松

【讨论】:

    【解决方案2】:

    经验法则是尽可能最短使用最轻锁。

    这里有一篇不错的文章:http://www.moserware.com/2008/09/how-do-locks-lock.html

    【讨论】:

      【解决方案3】:

      要遵循的一般规则是尽量减少持有锁的时间,并且不要调用不属于你的代码(例如事件、虚拟方法或 UI 线程) ) 同时持有锁。

      因此,计时器不应在持有锁时回调到 UI。如果它需要对锁定下的数据进行事务访问(读取、调用 UI、写入),那么它可能应该被设计为回滚和/或重试。

      【讨论】:

        【解决方案4】:

        就像 mfeingold 所说,尽可能避免它。在无法避免的地方,请注意以相同的顺序锁定两个线程!我的意思是,如果你有三个锁 A、B 和 C,如果你有以下锁模式

        • 线程 1:A->B->C
        • 线程 2:A->C->B

        那么可能会出现死锁...

        嵌套锁通常会降低性能,因为您必须锁定外部锁,即使您有时不需要确保在从另一个线程调用该方法的情况下行为正确。

        【讨论】:

          【解决方案5】:

          你为什么要这样做?这听起来很复杂且容易出错。

          委托给 UI 线程的计时器线程有什么用?

          这可能是必要的,但我的直接反应是,您可能需要退后一步,考虑您的设计是否不必要地迫使您陷入复杂的同步问题。

          【讨论】:

          • 你可能是对的,我从不反对重新评估。计时器线程在两种情况下委托回 UI 线程: 1. 调用一个对象,该对象输出到从 UI 线程实例化的 UI。并非此对象的所有实例都使用此类 UI。 (我很乐意为此提供一个好的模式。) 2. 调用第三方对象,必须从创建它的线程(在本例中为 UI 线程)调用该对象。
          • UI 操作是否需要同步发生(即您是否需要等到它们完成?) - 如果不需要,您可以考虑异步调用 UI 线程。这可能会让您避免潜在的死锁
          猜你喜欢
          • 1970-01-01
          • 2012-02-05
          • 2011-12-28
          • 1970-01-01
          • 2022-01-05
          • 1970-01-01
          • 2022-01-04
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多