我正在修复代码中的错误,并绞尽脑汁想出解决它的最佳方法。下面是这种死锁是如何发生的:
- 工作线程获取资源锁。
- GUI 线程尝试获取相同的资源锁,然后阻塞。
- 工作线程使用
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/