使用 proram STOP 在多线程上下文中抛出清除异常

Throwing Clear Exception in a Multithreaded Context with a proram STOP

提问人:Vero 提问时间:1/15/2023 更新时间:1/15/2023 访问量:45

问:

我有一个程序,它抛出另一个线程,如下所示:

#include <iostream>
#include <stdexcept>
#include <thread>

void op()
{
    std::cout << "OP HELLO WORLD" << std::endl;
    throw(std::runtime_error("OP ERROR"));
};

int main(int argc, char* argv[])
{
    //throw(std::runtime_error("MAIN ERROR"));
    std::thread t(op);
    t.join();
    std::cout << "MAIN HELLO WORLD" << std::endl;
};

我希望我的程序打印一条清晰的错误消息并停止。我知道我可以使用 or ,但是错误消息不清楚,并且不包含日志“OP ERROR”。std::abortstd::terminate

你能帮我编写一个程序,当失败时,它会退出并记录一条明确的错误消息。 当我尝试 , 块时也不起作用?std::futuretrycatch

C++ 多线程 异常 抛出

评论

0赞 Pete Becker 1/15/2023
捕获异常并显示消息。让异常从线程中转义会导致调用 。调用时没有必需的输出。std::terminatestd::terminate
0赞 Vero 1/15/2023
目标是我想知道错误是什么以及行和文件
0赞 sklott 1/15/2023
在这种情况下,请在错误消息中包含此信息。您可以创建宏来简化此操作。
0赞 sklott 1/15/2023
在我的答案中没有添加版本。std::future

答:

2赞 sklott 1/15/2023 #1

你在寻找这样的东西吗?

#include <iostream>
#include <stdexcept>
#include <thread>
#include <future>

void op()
{
    std::cout << "OP HELLO WORLD" << std::endl;
    throw(std::runtime_error("OP ERROR. File: " __FILE__ ", Line: "+ std::to_string(__LINE__)));
};

int main(int argc, char* argv[])
{
    //throw(std::runtime_error("MAIN ERROR"));
    auto res = std::async(op);
    try {
        res.get();
    } catch(const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return -1;
    }
    std::cout << "MAIN HELLO WORLD" << std::endl;
}

如果要输出所有线程的错误而不将异常返回到主线程,则可以设置自己的 .terminate()

#include <iostream>
#include <cstdlib>
#include <exception>
#include <thread>

void op()
{
    std::cout << "OP HELLO WORLD" << std::endl;
    throw(std::runtime_error("OP ERROR"));
}

void my_terminate()
{
    auto eptr = std::current_exception();
    try {
        if (eptr) {
            std::rethrow_exception(eptr);
        }
    } catch(const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }
    std::abort();
}

int main(int argc, char* argv[])
{
    std::set_terminate(my_terminate);
    //throw(std::runtime_error("MAIN ERROR"));
    std::thread t(op);
    t.join();
    std::cout << "MAIN HELLO WORLD" << std::endl;
}

出于某种原因,MSVC 使用每个线程的处理程序,要使其正常工作,您需要单独调用每个线程。set_termnate()

评论

0赞 Vero 1/15/2023
非常感谢。我正在寻找一些可以扔进工作线程而不是:)之外的东西再次感谢。但我认为从问题来看,这就是答案。我应该指定抛入工作线程并从工作线程停止程序。
1赞 rustyx 1/15/2023 #2

为避免调用 ,请确保异常不会在线程函数外部“泄漏”。std::terminate

void op()
{
    try {
        std::cout << "OP HELLO WORLD" << std::endl;
        throw std::runtime_error("OP ERROR");
    } catch (const std::exception& e) {
        std::cerr << "Exception: " << e.what() << std::endl;
        exit(1);
    }
}

如果要自动查看异常的文件和行号,在 C++ 中通常是不可能的

如果要在主线程中的单个位置捕获所有异常,则需要捕获它们并将它们传递给主线程。有一个有用的包装实用程序 std::p ackaged_task,它给出一个未来,您可以在其中等待结果或异常。

#include <iostream>
#include <stdexcept>
#include <thread>
#include <future>

void op()
{
    std::cout << "OP HELLO WORLD" << std::endl;
    throw std::runtime_error("OP ERROR");
}

int main(int argc, char* argv[])
{
    try {
        std::packaged_task<void()> task{&op};
        auto result = task.get_future();
        std::thread t{std::move(task)};
        t.join();
        result.get();
        std::cout << "MAIN HELLO WORLD" << std::endl;
    } catch (const std::exception& e) {
        std::cerr << "Exception: " << e.what() << std::endl;
    }
}