异步操作未完成时关闭对话框致程序崩溃的解决方法
问题描述
在对话框中通过std::async异步解码多张图片,正常运行无问题,但如果在异步任务未完成时关闭对话框,会在任务的return hh;处触发Debug Assertion Error。注释掉异步任务中的PostMessage调用后,崩溃不再出现。
相关代码如下:
类头文件
class CmytestDlg: public CDialog { protected: // Generated message map functions BOOL OnInitDialog() override; std::future<HBITMAP> futurebmps[12]; };
.cpp文件
BOOL CmytestDlg::OnInitDialog() { int totalJobs = 12; // 批量启动异步任务 for (int i = 0; i < totalJobs; i++) { futurebmps[i] = std::async(std::launch::async, [this](const int i, const std::string& name) { // 模拟耗时的图片解码操作 std::this_thread::sleep_for(std::chrono::seconds(10)); HBITMAP hh = nullptr; PostMessage(8888, i, 0); // 发送消息以展示图片 return hh; // <<<< 此处触发Debug Assertion Error(提前关闭对话框时) }, i, std::to_string(0)); } return CDialog::OnInitDialog(); }
消息处理函数
LRESULT CmytestDlg::OnRefreshAsyncView(WPARAM wParam, LPARAM lParam) { // 示例代码为空仍会触发问题 return 0; }
解决方案
1. 异步任务中先验证窗口有效性再发送消息
异步任务里直接调用MFC的PostMessage成员函数时,若对话框已销毁,this指针指向的对象已失效,会触发MFC的Debug断言。改为使用全局::PostMessage函数,并先通过GetSafeHwnd()获取有效窗口句柄:
// 替换原PostMessage调用 HWND hWnd = this->GetSafeHwnd(); if (hWnd != NULL) { ::PostMessage(hWnd, 8888, i, 0); }
即使窗口已销毁,GetSafeHwnd()返回NULL,全局PostMessage不会触发断言。
2. 对话框关闭时等待异步任务完成
在对话框的OnDestroy函数中,等待所有异步任务执行完毕,避免任务在对象销毁后继续运行:
void CmytestDlg::OnDestroy() { CDialog::OnDestroy(); // 等待所有异步任务完成 for (int i = 0; i < 12; i++) { if (futurebmps[i].valid()) { futurebmps[i].wait(); } } }
需在消息映射中添加ON_WM_DESTROY()宏,确保OnDestroy被正确调用。
3. 添加任务取消标志
在类中添加原子布尔变量作为取消标志,异步任务定期检查该标志,若已取消则提前退出,避免不必要的执行和消息发送:
// 类头文件中添加 #include <atomic> std::atomic<bool> m_bIsDialogClosing{false}; // 对话框关闭时设置标志 void CmytestDlg::OnClose() { m_bIsDialogClosing = true; CDialog::OnClose(); } // 异步任务中检查标志 futurebmps[i] = std::async(std::launch::async, [this](const int i, const std::string& name) { // 模拟耗时操作期间多次检查标志 for (int s = 0; s < 10; s++) { if (m_bIsDialogClosing.load()) { return (HBITMAP)nullptr; } std::this_thread::sleep_for(std::chrono::seconds(1)); } HWND hWnd = this->GetSafeHwnd(); if (hWnd != NULL && !m_bIsDialogClosing.load()) { ::PostMessage(hWnd, 8888, i, 0); } return (HBITMAP)nullptr; }, i, std::to_string(0));
内容的提问来源于stack exchange,提问作者user20716902
相关产品推荐
相关产品推荐

