线程管理
基本线程管理
启动一个线程
<1>最简单的一种类型
void do_some_work(); std::thread my_thread(do_some_work);
<2>函数对象的形式
#include<iostream> #include<thread> using namespace std; class Say_hello { public: void operator()(){cout<<"hello";} }; int main() { Say_hello hello; std::thread t(hello); t.join(); return 0; }
一旦开启一个线程,你需要明确地决定是否要等它结束 (通过join()函数 ),或让它自己后台运行(通过detach函数)
如果你不在std :: thread对象被销毁之前决定, 那么程序会被终止。如果你不想等待线程结束,也要保证在该线程结
束之前,它访问的数据都是有效的。
等待线程完成
thread_name.join();
thread_name.detach();
前面说了要在对象销毁之前确定是否等待线程结束。如果调用detach()函数,一般在开启线程之后马上调用,不会
出什么问题。但如果你要调用join()函数,应该小心选取调用该函数的位置。因为如果在线程开启之后,join()
函数调用之前抛出了异常,可能会跳过join()函数,导致出错。
一种解决方案:
class thread_guard { std::thread& t; public: explicit thread_guard(std::thread& t_):t(t_){}; ~thread_guard() { if(t.joinable()) { t.join(); } } thread_guard(thread_guard const&)=delete; thread_guard& operator=(thread_guard const&)=delete; }; void f() { std::thread t(hello); thread_guard g(t); do_something_in_current_thread(); }
这样在对象g析构的时候,会判定t是否为joinable,调用t.join(),无论其中是否抛出异常。
后台运行线程实例
void edit_document(std::string const& filename) { open_document_and_display_gui(filename); while(!done_editing()) { user_command cmd=get_user_input(); if(cmd.type==open_new_document) { std::string const new_name=get_filename_from_user(); std::thread t(edit_document,new_name); t.detach(); } else { process_user_input(cmd); } } }
传递参数给线程函数
传递参数给线程函数很简单,只需要将函数参数附加在线程的构造函数之后即可。
举例1
void f(int i,std::string const& s); std::thread t(f,3,”hello”);
一个线程对象t ,入口为函数f(3,"hello")
传递带引用的参数时
举例2
#include<iostream> #include<thread> using namespace std; void hello(int &i) { cout<<--i<<endl; } int main() { int j=3; cout<<j<<endl; std::thread t(hello,ref(j)); t.join(); cout<<j<<endl; return 0; }
通过ref()来传递对象的引用,结果输出:3,2,2