c++11 thread多线程 thread()、join()、detach()

目录

0.linux下thread编译命令

1.thread构造函数

1).以函数为参数

2).以可调对象为参数

3).以lambda表达式为参数

2.join()函数

3.detach()函数

4.joinable()函数


0.linux下thread编译命令

g++ 源文件名.cpp -std=c++11 -lpthread
或
g++ 源文件名.cpp -std=c++11 -lpthread -o 目标文件名

1.thread构造函数

//无参构造函数,创建空线程
thread() noexcept;

//初始化构造函数,执行fn函数,fn函数的参数由Args给出
template 
explicit thread(Fn&& fn, Args&&... args);

//拷贝构造函数,被禁用
thread(const thread&) = delete;

//move构造函数 不会(划掉)
thread(thread&& x) noexcept;

一般来说,最常用的就是初始化构造函数,因此就初始化构造函数的三种方式进行说明

1).以函数为参数

#include
using namespace std;

void print(){
    cout<<"子线程"<

运行结果:

可以发现,如果按照平时的思维,应该是先调用函数,函数结束之后再执行主线程。但是根据输出很明显不是这样。这就是线程的特别之处了。那是创建了子线程之后,就相当于子线程与主线程就分道扬镳了,各走各的路,因此执行的顺序是不可预估的。

2).以可调对象为参数

#include
using namespace std;

class A{
public:
    bool operator()(int i){
        cout<

使用可调对象时,必须重载"()"。

3).以lambda表达式为参数

#include
using namespace std;

int main(){
    auto a = [](){cout<<"lambda"<

2.join()函数

既然子线程被调用后,与主线程处于不同的道路了,那么考虑下面这个求10!的例子。

#include
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<

结果:

1
terminate called without an active exception
已放弃 (核心已转储)

很明显答案是错的,那么是为什么呢。我们说过子线程与主线程是两条不同的路,而且两者可以看做是同时进行的,也就是说在你还没有完成子进程的计算的时候,主进程已经进行到了cout<

join()函数实际上起到了一个阻塞的作用。就是说阻塞当前线程,直到调用join函数的线程结束之后,当前线程才能继续往下进行。

举个栗子,就好比一家人过节了爸爸妈妈在分别做菜,子线程是爸爸做饭,主线程就是妈妈做饭以及开饭。那么肯定为了时间效率,肯定爸爸妈妈分别负责不同的菜才能让一家人更快的吃上饭,也就是主线程子线程分别执行。既然是一家人吃饭,那肯定是一家人都准备好了,才能开饭。也就是说当妈妈昨晚菜之后(主线程执行到了开饭的前一步),那这时候肯定不能不等爸爸,一家人就开饭对吧,所以这时候一家人就必须等待爸爸做完菜(主线程进入了阻塞状态等待子线程完成)。只有当爸爸做好菜之后(子线程完成),一家人才能开开心心的开饭(主线程继续)。

经过这个例子,大家应该明白了join的重要性了吧。那么,对于10!这个问题,我们只要在输出前,加入join()方法,就可以等待计算结束之后再输出了。

#include
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<

运行结果:

3628800

3.detach()函数

与join()函数的暂时分工合作最后汇合不同,detach()函数是彻底的分道扬镳。也就是说调用detach()之后,主线程不再管子线程,就算主线程结束也没关系,子线程仍然在执行,只不过这时候子线程转到了后台运行,并且由c++运行时库管理。因为调用detach()之后子线程就失控了,所以使用detach()之后有时候会出现一些不可预计的错误,之后再来讨论。

#include
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<

上述程序的结果不可预计。

4.joinable()函数

一个线程只能一次join()或者一次detach()。joinable的返回值为true或者false,当当前线程返回值为true时,可以执行join()或者detach(),当返回值为false时,不能执行join()或者detach().

#include
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<

 

你可能感兴趣的:(c++11,thread)