thread::join()是个简单暴力的方法,主线程等待子进程期间什么都不能做,一般情形是主线程创建thread object后做自己的工作而不是简单停留在join上。thread::join()还会清理子线程相关的内存空间,此后thread object将不再和这个子线程相关了,即thread object不再joinable了,所以join对于一个子线程来说只可以被调用一次,为了实现更精细的线程等待机制,可以使用条件变量等机制。
异常环境下join,假设主线程在一个函数f()里面创建thread object,接着f()又调用其它函数g(),那么确保在g()以任何方式下退出主线程都能join子线程。如:若g()通过异常退出,那么f()需要捕捉异常后join
#include#include void do_something(int& i){ i++; } class func{ public: func(int& i):i_(i){} void operator() (){ for(int j=0;j<100;j++) do_something(i_); } public: int& i_; }; void do_something_in_current_thread(){} void f(){ int local=0; func my_func(local); boost::thread t(my_func); try{ do_something_in_current_thread(); } catch(...){ t.join();//确保在异常条件下join子线程 throw; } t.join(); } int main(){ f(); return 0; }
上面的方法看起来笨重,有个解决办法是采用RAII(资源获取即初始化),将一个thread object通过栈对象A管理,在栈对象A析构时调用thread::join.按照局部对象析构是构造的逆序,栈对象A析构完成后再析构thread object。如下:
#include#include #include using namespace std; class thread_guard:boost::noncopyable{ public: explicit thread_guard(boost::thread& t):t_(t){} ~thread_guard(){ if(t_.joinable()){//检测是很有必要的,因为thread::join只能调用一次,要防止其它地方意外join了 t_.join(); } } //thread_guard(const thread_guard&)=delete;//c++11中这样声明表示禁用copy constructor需要-std=c++0x支持,这里采用boost::noncopyable已经禁止了拷贝和复制 //thread_guard& operator=(const thread_guard&)=delete; private: boost::thread& t_; }; void do_something(int& i){ i++; } class func{ public: func(int& i):i_(i){} void operator()(){ for(int j=0;j<100;j++) do_something(i_); } public: int& i_; }; void do_something_in_current_thread(){} void fun(){ int local=0; func my_func(local); boost::thread t(my_func); thread_guard g(t); do_something_in_current_thread(); } int main(){ fun(); return 0; }
说明:禁止拷贝和复制的原因是防止栈对象thread_guard在超出了thread object对象生命期的地方使用。如果detach一个线程则没有上述这么麻烦,必经detach后就不管子线程了。