如何避免临界区和SendMessage之间的这种死锁?

时间:2014-05-07 12:44:25

标签: c++ multithreading winapi deadlock

我正在修复代码中的错误,并以最好的方式解决问题。以下是这种死锁的发生方式:

  1. 工作线程获取资源锁。
  2. GUI线程尝试获取相同的资源锁,并阻止。
  3. 工作线程使用SendMessage到GUI线程,因此阻塞。
  4. 被锁定的资源是一个关于网络状态的大数据结构 - 包括用户列表,他们的个人资料信息等。

    不幸的是,避免SendMessage电话是不现实的。这对程序更改对GUI的异步影响太大了。

    我的直觉是我的目标是避免在GUI线程中锁定。 GUI线程只需要对其锁定的数据进行读访问。这将解决此死锁,并可能修复应用程序中的其他响应时间问题。这是一种很好的直觉吗?

    要做到这一点,我觉得GUI应该使用 copy 来访问它需要的数据,而不需要锁定任何东西。

    所以,我如何获得此副本?如果我从GUI线程创建副本,那么我必须再次使用锁定,而我还没有解决任何问题。但我怎么能这样做呢?

    或.......我的方法完全错了?修复此错误的最佳方法是什么?


    修改:发现了一个类似的问题:EnterCriticalSection Deadlock

    一些可能的解决方案:

    • 不要使用来自工作线程的阻止GUI调用 - 而是使用PostMessage
    • 如果获取锁的GUI代码由工作程序触发,则从工作程序复制资源,并将堆指针传递给GUI。这样GUI就不需要锁定任何东西。这个我的代码的情况,所以我会尝试这个。
    • 在GUI中使用TryEnterCriticalSection,如果我无法进入,则恢复邮件提取,然后再安排另一次尝试,可能使用PostMessage
    • 删除工作人员对SendMessage的呼叫的锁定。

2 个答案:

答案 0 :(得分:4)

使用PostMessage而不是SendMessage将避免死锁。有两种方法可以做到这一点。如果您不想复制数据,则GUI线程消息处理程序必须获取锁以访问数据。所以会有争用,但没有僵局。为了避免所有争用,您必须在工作线程中复制数据。使用' new'将副本放入堆中。然后将堆指针作为PostMessage调用的参数传递。 GUI线程可以访问数据副本,然后它应该删除传递的指针。

答案 1 :(得分:1)

GUI端的锁定保护是什么类型的操作?如果它仅用于显示,那么操作几十毫秒后就可能无关紧要了。

因此只能尝试获取互斥锁(例如TryEnterCriticalSection())而不是等待它,如果它不可用,请稍后重新安排更新(再次使窗口无效以触发另一个绘制消息,排队自定义更新消息或其他)。