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

标签 c++ multithreading winapi deadlock

我正在修复代码中的错误,并绞尽脑汁想出解决它的最佳方法。下面是这种死锁是如何发生的:

  1. 工作线程获取资源锁。
  2. GUI 线程尝试获取相同的资源锁,然后阻塞。
  3. 工作线程使用 SendMessage 到 GUI 线程,因此阻塞。

被锁定的资源是一个关于网络状态的大数据结构——包括用户列表、他们的个人资料信息等。

不幸的是,避免 SendMessage 调用是不现实的。这对程序更改为与此处的 GUI 异步的内容影响太大。

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

为此,我认为 GUI 应该使用它需要访问的数据的拷贝,从而完全避免锁定任何内容。

那么,我如何得到这个拷贝?如果我从GUI线程创建拷贝,那么我必须再次使用锁,而且我还没有解决任何问题。但是我还能怎么做呢?

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


编辑:发现一个类似的问题:EnterCriticalSection Deadlock

一些可能的解决方案:

  • 不要使用来自工作线程的阻塞式 GUI 调用——而是使用 PostMessage
  • 如果获取锁的GUI代码是由worker触发的,则从worker中复制资源,并将堆指针传递给GUI。这样 GUI 就不需要锁定任何东西。这我的代码的情况,所以我会试试这个。
  • 在 GUI 中使用 TryEnterCriticalSection,如果我无法进入,则恢复消息推送并稍后安排另一次尝试,可能使用 PostMessage
  • 移除工作人员中对 SendMessage 调用的锁定。

最佳答案

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

关于c++ - 如何避免临界区和 SendMessage 之间的这种死锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23518208/

相关文章:

c# - 处理任务继续中某处抛出的异常

C++如何等待在另一个线程上执行的方法然后主线程完成(VS2010)

winapi - 使用输出设备作为Vista/Win7新声音API下的记录源?

c++ - 不兼容的 var 类型

c++ - 根据类型返回值

c++ - 将数据流式传输到 C++ 异常类中是否存在任何危险?

Python - 使用队列时多处理线程不会关闭

winapi - 创建 tagSECURITY_ATTRIBUTES 对象

c++ - 为什么内置类型的链式前缀递增/递减不是 C++ 的 UB?

c++ - 在开发国际象棋程序时,用给定的值初始化下面的方向数组有什么意义?