c++并发线程之创建线程、 join、detach、joinable、线程临时变量问题、ref使用

join

主线程等待子线程执行完


#include <thread>

using namespace std;

/*
a、每个进程都有一个主线程,这个主线程是唯一的,也就是一个进程只有一个主线程
b、当你执行一个可执行程序,产生一个进程后,这个主线程就随着这个进程默默的启动了

多线程(并发)
//线程并不是越多越好,每一个线程,都需要一个独立的堆栈空间(1M),线程之间的切换要保存很多中间状态
*/

void myprint()
{
    cout << "开始执行线程" << endl;
}

int main()
{
    //主线程从main函数开始执行
    //一般情况下,主线程执行完毕了,如果其他子线程还没有执行完毕,那么这些子线程也会被操作系统强行终止

    thread mythread(myprint);//1、创建了线程  2、线程执行起点myprint 3、myprint线程开始执行

    mythread.join();//希望主线程等待子线程,等待子线程执行完、阻塞主线程

    cout << "main func end" << endl;

    return 0;
}

detach

int main()
{

    thread mythread(myprint);

    //这个子线程就相当于被c++运行时库时刻接管,当这个子线程执行完成后,由运行时库负责清理该线程相关的资源
    mythread.detach();//主线程与子线程失去关联,子线程在后台运行
    //主线程运行结束,那进程就结束了,子线程的打印就不输出了,在后台执行
    for (int i = 0; i < 10; i++) {
        cout << "main func end" << i << endl;
    }

    return 0;
}

当调用了detach后,不能再调用join了

joinable

int main()
{

    thread mythread(myprint);

    //判断detach 或者 join能否被使用,如果返回true 就可以使用
    if (mythread.joinable()) {
        cout << "11111" << endl;
        mythread.join();
    }

    //当join 或者 detach被调用了,就返回false
    if (mythread.joinable()) {
        cout << "22222" << endl;
        mythread.detach();
    }
    

    for (int i = 0; i < 10; i++) {
        cout << "main func end" << i << endl;
    }

    return 0;
}

线程传参陷阱

创建线程,不要在参数中传递指针、引用

void myprint(const int &i, char * mybuf)
{
    cout << i << endl;
    cout << mybuf << endl;
}

int main()
{
    int var = 10;
    int& myvar = var;
    char buf[] = "this is buffer";
    //myvar这里是引用,本应该不会进行拷贝,但是确拷贝了,
    //所以就算主线程结束了,myvar回收了, myprint函数中的i也不会报错
    //线程对参数中的引用也会进行拷贝
    //但是指针不会拷贝,如果主线程的buf回收了,myprint中的 mybuf就会报错
    thread mythread(myprint, myvar,buf);

    mythread.detach();

    return 0;
}

在thread的参数中 创建临时对象传递给线程,一定能保证在主线程执行完之前,创建完成,thread中的参数,引用也会被拷贝一次

class A
{
public:
    A(int i) :m_i(i) { cout << "传参构造函数" << this << endl; }
    A(const A& a) :m_i(a.m_i) {cout << "拷贝构造函数" << this << endl; }
    ~A() { cout << "析构函数" << this << endl; }
int m_i;
};

void myprint(const int i, A a)
{
    cout << a.m_i << endl;
}

int main()
{
    int var = 10;
    int& myvar = var;
    char buf[] = "this is buffer";
    //添加A 临时对象,确保在main函数执行完之前,就能构造类对象
    //这样就执行了一次 创建临时对象,传参构造函数 和一次拷贝构造函数,
    thread mythread(myprint,var,A(var));

    mythread.detach();

    return 0;
}

通过线程id看是在主线程中做的创建临时对象还是在 子线程创建的临时对象

带入普通变量,隐式转换成A类对象

class A
{
public:
    A(int i) :m_i(i) { cout << "传参构造函数" << this  << "thread id =" << this_thread::get_id() << endl; }
    A(const A& a) :m_i(a.m_i) {cout << "拷贝构造函数" << this << "thread id =" << this_thread::get_id() << endl; }
    ~A() { cout << "析构函数" << this << "thread id =" << this_thread::get_id() << endl; }
int m_i;
};

void myprint(const int i, A a)
{
    cout << a.m_i << endl;
}

int main()
{
    int var = 10;

    //主线程id
    cout << "主线id是" << this_thread::get_id() << endl;

    thread mythread(myprint,var,var);

    mythread.join();

    return 0;
}

说明带入变量做隐式转换,创建A类是在子线程中完成,如果主线程执行结束了,释放了var,就会出问题
在这里插入图片描述

带入A类对象,传参构造

在这里插入图片描述

说明创建临时变量,构造函数是在主线程中完成的
在这里插入图片描述

如何避免线程参数 进行拷贝构造呢?

有时候带入的是引用,并且修改了引用的值,但是如果进行了拷贝构造,那么引用就没有意义了,修改的值 也仅仅只是修改 拷贝后对象的值, 如果 禁止拷贝构造?
仅仅需要在thread中的 参数 加上 ref就可以

void myprint(A &a)
{
    a.m_i = 20;
    cout << "myprint" << a.m_i << endl;
    return;
}

int main()
{
    int var = 10;

    //主线程id
    cout << "主线id是" << this_thread::get_id() << endl;
    A a(var);
    cout << "111 a.m_i = " << a.m_i << endl;
	//加上ref后,就不会对a进行拷贝了,m_1也能被成功修改
    thread mythread(myprint,ref(a));


    mythread.join();
    cout << "222 a.m_i = " << a.m_i << endl;
    return 0;
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值