c++ 如果在异步操作仍在进行时关闭对话框,则应用程序崩溃

jhkqcmku  于 2023-02-06  发布在  其他
关注(0)|答案(2)|浏览(95)

首先,我不熟悉使用异步,所以下面的方法可能是完全错误的。我目前正在解码多个图像,并显示在一个对话框窗口。
只要我不试图在解码仍在运行时关闭对话框,这就可以正常工作。
如果关闭对话框,则会在return hh;处收到调试Assert错误
在我的类头中,我有:

class CmytestDlg: public CDialog
{

protected:
    // Generated message map functions
    BOOL OnInitDialog() override;
    std::future<HBITMAP> futurebmps[12];

};

在.cpp中:

BOOL CmytestDlg::OnInitDialog()
{
    int totalJobs = 12;

    // Queue up all the items,
    for (int i = 0; i < totalJobs; i++)
    {
        futurebmps[i] = std::async(std::launch::async,
            [this](const int i, const std::string& name) {

        // This line is just here to simulate a long running image decode
        std::this_thread::sleep_for(std::chrono::seconds(10));

        HBITMAP hh = nullptr;
        PostMessage(8888, i, 0); // Send a message to display the image
        return hh; // <<< Debug Assertion Error Here (If I close dialog to soon)
    
        }, i, std::to_string(0));
        
}

绘制图像的消息由OnRefreshAsyncView处理:

LRESULT CmytestDlg::OnRefreshAsyncView(WPARAM wParam, LPARAM lParam)
{
    // For the purpose of a minimal demo, even if this is empty It still casuses the issue.
    return 0;
}

我相信这个问题是由调用PostMessage触发的,如果我注解掉这一行,我就不会再遇到崩溃。
我如何安全地处理对话框关闭的情况?这样我就可以防止这种崩溃。

j1dl9f46

j1dl9f461#

我的通灵能力表明,您的ATL/MFC程序正在AssertPostMessage调用,因为窗口句柄在您关闭/销毁它之后变得无效。在PostMessage调用中间的某个地方有一个ASSERT,表明m_hWnd示例是非空的。因此,该Assert引起了对代码中一个真正错误的注意。
PostMessage是Win32 API的 Package 器:PostMessage当您在另一个线程上调用 Package 器函数时,它可能会Assertm_hWnd(或类似的HWND成员)为非空。
考虑编写额外的(线程安全的)代码(带有互斥锁),以防止在句柄上处理WM_CLOSE/WM_DESTROY的同时或之后调用PostMessage。
大概是这样的

void CmytestDlg::SafePostMessage(UINT uMsg, WPARAM wp, LPARAM lp)
{
    std::unique_lock<std::mutex> lck(_mutex);
    if (_isHwndValid)
    {
        PostMessage(uMsg, wp, lp);
    }
}

void CmytestDlg::OnClose(...)
{
    std::unique_lock<std::mutex> lck(_mutex);
    _isHwndValid = false;
}

其中OnClose是WM_CLOSE消息的处理程序,isHwndValid是类的bool成员,在创建窗口时被设置为true,_mutex是std::mutex。

3j86kqsm

3j86kqsm2#

要扩展selbie's answer
如果希望线程提前停止,可以将该标志转换为std::atomic,并在计算期间定期检查它,例如:

std::mutex _mutex;
std::atomic<bool> _shutdown = false;

void CmytestDlg::LongRunningThing()
{
   do_something();
   if (_shutdown) return;
   do_something_else()
   if (_shutdown) return;
   ...
}

void CmytestDlg::SafePostMessage(UINT uMsg, WPARAM wp, LPARAM lp)
{
    std::unique_lock<std::mutex> lck(_mutex);
    if (!_shutdown)
    {
        PostMessage(uMsg, wp, lp);
    }
}

void CmytestDlg::OnClose(...)
{
    std::unique_lock<std::mutex> lck(_mutex);
    _shutdown = false;
}

相关问题