You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

异步操作未完成时关闭对话框致程序崩溃的解决方法

问题描述

在对话框中通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 15:25:23