从线程捕获异常时退出程序

Posted

技术标签:

【中文标题】从线程捕获异常时退出程序【英文标题】:Exit program when catch exception from thread 【发布时间】:2018-03-16 03:59:14 【问题描述】:

参考Catching exception from worker thread in the main thread,我创建了一个工作线程,它向主线程抛出异常然后终止程序(逻辑是在发生异常时退出程序)。

我似乎没有正确实现它,因为程序直到调用 exit() 的那一行才会执行。

示例代码:

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

static std::exception_ptr _exceptionPtr = nullptr;

struct WorkerThread

    std::thread thread;

    void doSomething()
    
        int seconds = 0;
        bool shouldStop = false;

        while(shouldStop == false)
        
            std::this_thread::sleep_for(std::chrono::milliseconds(1000));
            std::cout << "time passed : " << ++seconds << "seconds" << std::endl;

            if (seconds == 10) // something bad happened 10 seconds later
            
                try
                
                    shouldStop = true;
                    throw std::runtime_error("something really bad happened");
                
                catch (const std::runtime_error &ex)
                
                    _exceptionPtr = std::current_exception();
                
            
        
    

    void run()
    
        thread = std::thread([this]  doSomething(); );
        thread.detach();
    
;

int main(int argc, char *argv[])

    WorkerThread workerThread;

    try
    
        workerThread.run();
    
    catch (...)
    
        if (_exceptionPtr)
        
            try
            
                std::rethrow_exception(_exceptionPtr);
            
            catch (std::runtime_error &ex)
            
                // terminates program if exception happens
                std::cout << "Program will now exit" << std::endl;
                exit(EXIT_FAILURE); // but program never executes till here
            
        
    

    for (;;)
    
        // do A
        // do B
        // do C
        // do ...
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        std::cout << "waiting for thread..." << std::endl;
    

    return 0;

我错过了什么?当前的方法是否正确?如果没有,我该怎么做?谢谢

【问题讨论】:

你需要在for循环中测试worker线程是否出错,而不是for run()函数,它会立即返回。 How can I propagate exceptions between threads?的可能重复 看起来工作线程实际上并没有在抛出。您正在捕获异常并设置共享 ptr,但不会重新抛出。我看不出你在 .run 周围的捕获有什么可捕获的。 您是否考虑过将回调函数传递给线程并让它以这种方式报告错误? @liliscent 你是对的 【参考方案1】:

在您发布的代码中,异常检查仅发生一次,并且可能在线程启动之前发生。

您还从主机线程中捕获了一个错误,但您抛出的错误是在第二个线程上。

我通过在检查异常之前等待第二个线程完成来解决了这些问题。

无论如何,跨线程抛出异常的典型方法可以在这里找到:How can I propagate exceptions between threads?

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

static std::exception_ptr _exceptionPtr = nullptr;

struct WorkerThread

    std::thread thread;

    void doSomething()
    
        int seconds = 0;
        bool shouldStop = false;

        while (shouldStop == false)
        
            std::this_thread::sleep_for(std::chrono::milliseconds(1000));
            std::cout << "time passed : " << ++seconds << "seconds" << std::endl;

            if (seconds == 10) // something bad happened 10 seconds later
            
                try
                
                    shouldStop = true;
                    throw std::runtime_error("something really bad happened");
                
                catch (const std::runtime_error &ex)
                
                    _exceptionPtr = std::current_exception();
                
            
        
    

    void run()
    
        thread = std::thread([this]  doSomething(); );
        //thread.detach();
    
;

int main(int argc, char *argv[])

    WorkerThread workerThread;

        workerThread.run();
        workerThread.thread.join();
        if (_exceptionPtr)
        
            try
            
                std::rethrow_exception(_exceptionPtr);
            
            catch (std::runtime_error &ex)
            
                // terminates program if exception happens
                std::cout << "Program will now exit" << std::endl;
                exit(EXIT_FAILURE); // but program never executes till here
            
        

    for (;;)
    
        // do A
        // do B
        // do C
        // do ...
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        std::cout << "waiting for thread..." << std::endl;
    

    return 0;

【讨论】:

我可能错了,但是如果让主机线程等待工作线程完成,它不会失去线程的意图吗?我希望它们同时运行。 @HohoHaha 在这种情况下是的,但一般来说不是。您可以在调用等待命令之前完成工作。你可以有不止一个线程在等待。如果发生错误,您还可以有一个轮询循环。【参考方案2】:

应该在 for 循环而不是 workerThread.run() 中捕获异常,因为 run() 将立即退出。

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

static std::exception_ptr _exceptionPtr = nullptr;

struct WorkerThread

    std::thread thread;

    void doSomething()
    
        int seconds = 0;
        bool shouldStop = false;

        while (shouldStop == false)
        
            std::this_thread::sleep_for(std::chrono::milliseconds(1000));
            std::cout << "time passed : " << ++seconds << "seconds" << std::endl;

            if (seconds == 10) // something bad happened 10 seconds later
            
                try
                
                    shouldStop = true;
                    throw std::runtime_error("something really bad happened");
                
                catch (const std::runtime_error &ex)
                
                    _exceptionPtr = std::current_exception();
                
            
        
    

    void run()
    
        thread = std::thread([this]  doSomething(); );
        thread.detach();
    
;

int main(int argc, char *argv[])

    WorkerThread workerThread;

    workerThread.run();



    for (;;)
    
        // do A
        // do B
        // do C
        // do ...
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        std::cout << "waiting for thread..." << std::endl;

        if (_exceptionPtr)
        
            try
            
                std::rethrow_exception(_exceptionPtr);
            
            catch (std::runtime_error &ex)
            
                // terminates program if exception happens
                std::cout << "Program will now exit" << std::endl;
                exit(EXIT_FAILURE); // but program never executes till here
            
        
    

    return 0;

感谢@liliscent

【讨论】:

以上是关于从线程捕获异常时退出程序的主要内容,如果未能解决你的问题,请参考以下文章

线程以未捕获的异常退出,AyncTask #2 致命错误

Android视图:未捕获的处理程序:线程主因未捕获的异常而退出

java语言中application异常退出和线程异常崩溃的捕获方法,并且在捕获的钩子方法中进行异常处理

转 C#WinForm程序异常退出的捕获继续执行与自动重启

linux c开发: 在程序退出时进行处理

线程以代码 0 (0x0) 退出,没有未处理的异常