MFC ResumeThread 和 std::condition_variable 等待后偶尔线程同步失败

Posted

技术标签:

【中文标题】MFC ResumeThread 和 std::condition_variable 等待后偶尔线程同步失败【英文标题】:Occassional thread sync fail after MFC ResumeThread and std::condition_variable wait 【发布时间】:2021-09-02 09:31:08 【问题描述】:

背景 我正在完成将我的 MFC 框架项目从原型升级到 alpha 生产代码。任务是同步其线程。我混合使用了互斥锁、条件变量和二进制信号量。这在很大程度上是成功的。与我的问题最相似的 *** 案例是 std::condition_variable wait() and notify_one() synchronization。

问题 但是,有时,在新建从 CWinThread (RxWs2SocketThread) 派生的某个类之后会出现原子性问题。 RxWs2SocketThread 切换到新类的线程并执行 InitInstance 并再次切换回来,就像它应该做的那样。在单线程程序中,当调用 ResumeThread 时,线程切换到 InitInstance 没有问题,但在我的多线程程序中,我必须控制切换。代码如下:

在第 95 行和第 102 行之间偶尔会发生失败。这是显示成功切换的应用日志:

左边的数字是线程号。行号在括号中,如 [100]。请注意,[100] 是第 102 行实际 wait 调用的检测工具。此应用程序日志显示了失败的示例:

在此日志中,notify_one 发生在 wait 之前,这会导致程序挂起。请注意应用日志中的第 [100] 行,它表示第 [102] 行代码中的 wait 调用。

问题 这告诉我我需要在 ResumeThreadstd::condition_variable.wait() 调用之间提供原子性。我怎样才能做到这一点?我必须恢复类线程,否则不会调用InitInstance,但是恢复线程后我不能等待。

【问题讨论】:

【参考方案1】:

原来答案就在我面前。 在代码行 101 上,在rxWs2SocketInitInstanceMu mutex 上获得了一个锁。我所要做的就是将锁移到第 95 行之前ResumeThread

编辑1: 我为future/promise 切换了std::condition_varialble 同步原语。前者需要使用单独的锁定,当锁定语句放在ResumeThread 之前时确实有效,但这会导致容易出错的维护。 future/promise 原语被设计为一次性的,这就是它在我的代码中的使用方式。

请注意,std::promise 对象只能使用一次(参见 cppreference)

.

【讨论】:

以上是关于MFC ResumeThread 和 std::condition_variable 等待后偶尔线程同步失败的主要内容,如果未能解决你的问题,请参考以下文章

Windows API一日一练 50 SuspendThread和ResumeThread函数

c++17 语言扩展和 std:c++17 标志

为啥 -ansi 和 -std=c++11 在 g++ 中会发生冲突?

如何使用自动工具编译带有 clang 和选项 -std=c++11 的项目

Cython -std=c++11 错误,同时使用 C 和 C++

警告:扩展初始化列表仅适用于 -std=c++11 或 -std=gnu++11 [默认启用]