Visual Studio 在C++/MFC中使用线程获取异常

umuewwlo  于 2023-04-22  发布在  其他
关注(0)|答案(1)|浏览(202)

我在程序中遇到了这个异常:0x 00007 FFD 187 CF 61 E(ucrtbase.dll)我的项目是C++/MFC,源代码如下。
我确认这段代码在我的另一个项目,这是一个控制台项目。

ReloadWatchdog.h

#pragma once
class ReloadWatchdog
{
public:
    static void Reload();
};

ReloadWatchdog.cpp

#include "pch.h"
#include "ReloadWatchdog.h"
#include <thread>
void ReloadWatchdog::Reload()
{
    while (true)
    {
        using namespace std::chrono_literals;
        std::this_thread::sleep_for(std::chrono::minutes(4));
        try {
            call_method();
        }
        catch (...) {
        }
    }
}

主要

BOOL CWatchDogPI336Dlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // ↓this occured exception
    std::thread th1(ReloadWatchdog::Reload);

    return TRUE;
}
bfnvny8b

bfnvny8b1#

C++11的std::thread被设计为拥有底层操作系统线程。默认情况下,std::thread对象需要比操作系统线程更长寿。
这种设计是可以理解的,但有一个不幸的后果:只有当std::threaddestructor开始执行时,才能观察到在两个生命周期之间没有保持不变式。因为太晚了,无法抛出异常,所以实现调用std::terminate()
这是正在发生的事情:

BOOL CWatchDogPI336Dlg::OnInitDialog()
{
    // ...
    std::thread th1(ReloadWatchdog::Reload);

    return TRUE;
} // th1 is destroyed here

根据具体需要,有三种解决方案:
1.在th1上调用detach(),这放宽了生存期要求。std::thread示例和操作系统线程可以生存任意时间。
1.使th1成为CWatchDogPI336Dlg的非静态类成员。这并不能缓解核心问题,而不是推迟它。当~CWatchDogPI336Dlg完成时,操作系统线程必须运行完成。
1.使用C++20的std::jthread代替。有趣的区别是它的destructor将等待操作系统线程终止。这是一个阻塞调用,所以它在这里并不立即适用。

相关问题