首页 > 其他 > 详细

2.1.3 在异常环境下的等待

时间:2021-05-17 22:33:28      阅读:32      评论:0      收藏:0      [点我收藏+]

  如前所述,可以通过join()来等待线程完成。但是,当程序变得复杂时,程序的出口可能不止一个,如果主线程(我觉得它是,就这样吧)打算等待子线程完成,就需要仔细选择在代码的哪个位置调用join(),避免因为程序异常,跳过了对join()的调用。

struct func
{
    int& i;
    func(int& i_) :i(i_) {}

    void operator()()
    {
        for (unsigned j = 0; j < 1000000; j++)
        {
            do_somnething(i);    // 不断对引用的访问
        }
    }
};

void f()
{
    int some_local_state = 0;
    func my_func(some_local_state);
    std::thread t(my_func);
    try
    {
        do_something_in_current_thread();
    }
    catch(...)
    {
        t.join();            // 异常中断
        throw;
    }
    t.join();                 // 正常退出    
}

  以上示例,使用了try/catch块,以确保线程t在函数f退出前结束,无论函数是正常退出还是异常中断。但是使用ry/catch很啰嗦,而且容易将作用域弄乱,所以不是一个理想的方案。可以按以下方式进行改写。

class thread_guard
{
    std::thread& t;
public:
    explicit thread_guard(std::thread& t_):t(t_){}
    ~thread_guard()
    {
        if(t.joinable())   // ① 一个给定的执行线程join()只能被调用一次,所以,首先判断线程是否已经被结合
        {
            t.join();       //
        }
    }

   // ③ 拷贝构造函数和拷贝赋值运算符被标记为delete,以确保类对象不会被复制或拷贝,复制和拷贝这样一个对象可是很危险的
    thread_guard(thread_guard const&) = delete;   
    thread_guard& operator=(thread_guard const&) = delete;
}

struct func;    // 定义同上

void f()
{
    int some_local_state = 0;
    func my_func(some_local_state);
    std::thread t(my_func);
    thread_guard g(t);

    do_something_in_current_thread();
}    //

   在当前线程执行到函数f末尾时,函数内的局部对象会按照定义顺序的逆序被销毁。因此,thread_guard对象g首先被销毁。thread_guard类的析构函数内,线程t被结合②。所以,线程t执行完毕后,thread_guard对象g才会被成功销毁,g销毁后,继续逆序销毁其它局部对象,这样,避免了线程t执行完之前,some_local_state对象就被销毁了,从而引发错误。而且,这种方式,即便是当函数do_something_in_current_thread引发异常而退出的情况下也会发生上述过程。

2.1.3 在异常环境下的等待

原文:https://www.cnblogs.com/tgcf/p/14777413.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!