在c++11并发编程历程(2)中我分享了在非异常的情况下调用join(),本文来看一下在异常环境下调用join
()进行等待
话不多说,上代码
#include <iostream>
#include <thread>
using namespace std;
struct func
{
int &m_i;
func(int &i) :m_i(i) {}
void operator()()
{
for (int i = 0; i < 1000; ++i)
{
int addr = m_i++;
cout << addr << endl;
}
}
};
void f()
{
int a = 0;
func my_func(a);
thread my_thread(my_func);
try {
int a = 0;
throw -1;
int b = 1 / a;
}
catch (int)
{
if (my_thread.joinable())
{
my_thread.join();
cout << "异常退出,等待新线程正常结束" << endl;
}
}
}
int main()
{
f();
}
关于其中看不懂的语法点,可以参考博主的c++11专栏和c++专栏文章
运行结果部分截图如下:
从上面代码中可以看到,我们在异常情况下也会去等待新线程运行结束,看似好像能解决问题,但是存在问题也很多,代码啰嗦,作用域混乱。
下面介绍一个简单清晰的机制,RAII(百度百科称为“资源获取就是初始化”),并提供一个类,在它的析构函数中使用join();
#include <iostream>
#include <thread>
using namespace std;
struct func
{
int &m_i;
func(int &i) :m_i(i) {}
void operator()()
{
for (int i = 0; i < 1000; ++i)
{
int addr = m_i++;
cout << addr << endl;
}
}
};
class thread_man
{
public:
explicit thread_man(thread &my_thread) :m_thread(my_thread) {}
~thread_man()
{
if (m_thread.joinable())
{
m_thread.join();
cout << "join end" << endl;
}
}
private:
thread &m_thread;
};
void f()
{
int a = 0;
func my_func(a);
thread my_thread(my_func);
thread_man my_thread_man(my_thread);
}
int main()
{
f();
}
运行结果如下:
这种写法巧妙之处在于因为函数f结束的时候需要按照构造顺序反序销毁,例中f函数执行到最后一行完会反向先销毁my_thread_man,而销毁类对象my_thread_man需要调用析构函数,析构函数中会检测新线程是否执行完成,若无,则等待新线程执行完成后析构类对象my_thread_man
人,总是要有一点精神的,不是吗