线程管理
基本线程管理
启动一个线程
<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