1. 发起线程
C++ thread支持 普通函数、lambda、可调用对象,作为线程启动执行的任务
创建完thread对象后,必须调用join()或者detach()函数,为什么后面源码会讲到
1.1 普通函数
#include <thread>
#include <stido.h>
using namespace std;
void func()
{
printf("func()\n");
}
int main()
{
/////////////////////// 接收普通函数
thread t(func);
t.join(); // 需要调用join或detach,否则thread析构的时候调用terminate()则崩溃
///////////////////////
return 0;
}
1.2 普通函数,传入参数
使用std::bind将函数指针和参数绑定然后传入给thread对象
// 省略掉头文件...
void func(vector<int>& vec)
{
for (auto item : vec)
cout << item << " ";
}
int main()
{
vector<int> vec{ 1, 2, 3, 4, 5};
///////////////////// 使用std::bind
thread t(std::bind(func, vec));
/////////////////////
t.join();
return 0;
}
1.3 lambda
int main()
{
thread t([](){
cout << "lambda func()" << endl;
});
t.join();
return 0;
}
1.4 可调用对象
// 省略头文件 ....
struct A
{
void operator()()
{
cout << "operator()()" << endl;
}
};
int main()
{
thread t(A());
t.join(); // 这里报错
return 0;
}
上面t.join()报错,是因为 thread t(A()); 把这一行当作了函数声明. 解决方法是:
thread t( (A()) ); 在A()再套上一层小括号。
thread t { A() }; 或者是这样,列表初始化
2. MSVC的thread源码
thread UML类图
2.1 thread构造来创建线程
通过下面两张图可知。创建thread对象的时候,传入函数和参数作为线程执行的任务。如果函数的参数是左值,那么当我们传入一个参数的时候,会报错Invoke不匹配。这就是因为thread内部去掉了参数的引用。
2.2 join()和detach()函数
2.3 thread的析构
之前说过,创建完thread对象必须调用detach()或者join(), 否则会发生异常
所以根据上面源码得知, 一个线程对象join()或者detach()会把成员变量_Thr置为空。那么一个线程执行完,就可以再次给这个对象重新赋值,如下:
void func()
{
cout << "id: " << std::this_thread::get_id() << " func()" << endl;
}
int main()
{
thread t(func);
t.join();
// 第一个线程已经执行完
t = thread(func); // 给t对象重新赋值一个线程对象
t.join();
return 0;
}