目录
0.linux下thread编译命令
g++ 源文件名.cpp -std=c++11 -lpthread
或
g++ 源文件名.cpp -std=c++11 -lpthread -o 目标文件名
1.thread构造函数
//无参构造函数,创建空线程
thread() noexcept;
//初始化构造函数,执行fn函数,fn函数的参数由Args给出
template <class Fn, class... Args>
explicit thread(Fn&& fn, Args&&... args);
//拷贝构造函数,被禁用
thread(const thread&) = delete;
//move构造函数 不会(划掉)
thread(thread&& x) noexcept;
一般来说,最常用的就是初始化构造函数,因此就初始化构造函数的三种方式进行说明
1).以函数为参数
#include<bits/stdc++.h>
using namespace std;
void print(){
cout<<"子线程"<<endl;
cout<<"子线程"<<endl;
cout<<"子线程"<<endl;
}
int main(){
thread my(print);
cout<<"主线程"<<endl;
my.join();
return 0;
}
运行结果:
可以发现,如果按照平时的思维,应该是先调用函数,函数结束之后再执行主线程。但是根据输出很明显不是这样。这就是线程的特别之处了。那是创建了子线程之后,就相当于子线程与主线程就分道扬镳了,各走各的路,因此执行的顺序是不可预估的。
2).以可调对象为参数
#include<bits/stdc++.h>
using namespace std;
class A{
public:
bool operator()(int i){
cout<<i<<endl;
}
};
int main(){
A a;
int i = 1;
thread my(a,i);
cout<<"主线程"<<endl;
my.join();
return 0;
}
使用可调对象时,必须重载”()”。
3).以lambda表达式为参数
#include<bits/stdc++.h>
using namespace std;
int main(){
auto a = [](){cout<<"lambda"<<endl;};
thread my(a);
cout<<"主线程"<<endl;
my.join();
return 0;
}
2.join()函数
既然子线程被调用后,与主线程处于不同的道路了,那么考虑下面这个求10!的例子。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL ans = 1;
void cal(int n){
for(int i = 1;i <= n;++i) ans *= i;
}
int main(){
int n = 10;
thread my(cal,10);
cout<<ans<<endl;
return 0;
}
结果:
1
terminate called without an active exception
已放弃 (核心已转储)
很明显答案是错的,那么是为什么呢。我们说过子线程与主线程是两条不同的路,而且两者可以看做是同时进行的,也就是说在你还没有完成子进程的计算的时候,主进程已经进行到了cout<<ans<<endl;这一步了,而此时的ans还没有计算完成,所以出现了错误。那么怎么解决这个问题呢?这就要用到join()函数了。
join()函数实际上起到了一个阻塞的作用。就是说阻塞当前线程,直到调用join函数的线程结束之后,当前线程才能继续往下进行。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL ans = 1;
void cal(int n){
for(int i = 1;i <= n;++i) ans *= i;
}
int main(){
int n = 10;
thread my(cal,10);
my.join();
cout<<ans<<endl;
return 0;
}
运行结果:
3628800
3.detach()函数
与join()函数的暂时分工合作最后汇合不同,detach()函数是彻底的分道扬镳。也就是说调用detach()之后,主线程不再管子线程,就算主线程结束也没关系,子线程仍然在执行,只不过这时候子线程转到了后台运行,并且由c++运行时库管理。因为调用detach()之后子线程就失控了,所以使用detach()之后有时候会出现一些不可预计的错误,之后再来讨论。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL ans = 1;
void cal(int n){
for(int i = 1;i <= n;++i) ans *= i;
}
int main(){
int n = 10;
thread my(cal,10);
my.detach();
cout<<ans<<endl;
return 0;
}
上述程序的结果不可预计。
4.joinable()函数
一个线程只能一次join()或者一次detach()。joinable的返回值为true或者false,当当前线程返回值为true时,可以执行join()或者detach(),当返回值为false时,不能执行join()或者detach().
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL ans = 1;
void cal(int n){
for(int i = 1;i <= n;++i) ans *= i;
}
int main(){
int n = 10;
thread my(cal,10);
if(my.joinable()) my.join();
cout<<ans<<endl;
return 0;
}