• 三、线程传参


    一、thread线程对象的参数详解

    1、线程函数参数是值传递

    void mythread(int i){//如果不对i修改,可以改成const int i
        cout<<&i<<endl;
    }
    int main(){
        int a=1;
        thread thread1(mythread,a);//第一个参数是线程函数名,后面的是线程函数的参数,值传递
        thread1.join();//使用detach不会报错
        cout<<&a<<endl;
    }

    将a传入后,线程入口函数采用值传递方式先将a拷贝得到副本(即i)。所以此时的 i 和 a 的地址不同。

    值传递时,使用detach()也不会出问题。

    2、线程函数引用传递参数

    当线程入口函数的参数列表中有引用,这个时候很多问题。

    (1)构造thread对象时直接使用主线程中的对象

    定义线程函数时引用的参数必须加const!因此只能只读。

    int mythread(const int& i){//不加const会报错!
        cout<<"thread:"<<&i<<endl;
        return 0;
    }
    int main(){
        int a=1;
        thread thread1(mythread,a);
        thread1.join();//使用detach也不会出问题
        cout<<&a<<endl;
        return 0;
    }

    此时i的地址和a的地址并不相同。虽然线程函数参数是引用,但构建thread1时还是拷贝出了一个a副本,线程函数引用的是副本。

    (2)真正使用引用的方法:ref函数

    这时在定义线程函数时,参数前的const可以去掉。

    int mythread(int& i){//const去掉
        i+=1;
        cout<<"thread:"<<&i<<endl;
        cout<<"i= "<<i<<endl;
        return 0;
    }
    int main(){
        int a=1;
        thread thread1(mythread,ref(a));//真正意义上的引用
        thread1.join();//detach()也不会出错
        cout<<"main:"<<a<<endl;
        cout<<"main地址:"<<&a<<endl;
        return 0;
    }

    3、传递字符串

    int mythread(char* buf){
    //    cout<<buf<<endl;
    //    cout<<&buf<<endl;
        cout<<&buf<<endl;
        cout<<"thread end"<<endl;
        return 0;
    }
    int main(){
        char buf[]="i love china";
        thread thread1(mythread,buf);//数组是指针传递,传的是第0个元素的地址。
        thread1.join();
        cout<<"main"<<endl;
        return 0;
    }

    字符数组是数组,传递属于指针传递,数组传递的是第0个元素的地址,万一主线程执行完,buf回收,而子线程用到了buf[888]类似于这样的地址,那么就相当于指向了一个回收的内存地址,野指针现象发生。!!

    如果在定义线程入口函数时,隐式转换成string。存在的问题是,万一主线程执行完了,子线程还没转换完,还是会出现野指针的现象,程序还是会报错。

    因此对于字符串、类对象可以在构造thread对象时,构建临时对象即可:

    class A{
    public:
        int& m_i;
        A(int& i):m_i(i){}
        A(const A& a):m_i(a.m_i){cout<<"拷贝构造函数执行"<<endl;}
        ~A(){cout<<"析构函数执行"<<endl;}
    }
    void mythread(string& buf,const A& a){//引用传递
        cout<<"thread"<<endl;
    }
    
    int main(){
        int a=9;
        char buf[]=="ilovechina"
        thread thread1(mythread,string(buf),A(a));//构造两个临时对象
        thread1.detach();//join、detach都没问题
        cout<<"main end"<<endl;
        return 0;
    }

    4、智能指针

    #include <iostream>
    #include <thread> //线程
    using namespace std;
    
    void prt(unique_ptr<int> p){
        cout<<"子线程开始了"<<endl;
    }
    int main(){
        unique_ptr<int> myptr(new int(100));
        std::thread myobj(prt,std::move(myptr));//move将myptr给了临时的指针变量,之后myptr就没了,
        //如果用detach,万一myprt指向的内存回收了,那么子线程的这个指针就指向了一个被回收的内存地址,就会出错,所以这个时候不能用detach
        //只能用join
        myobj.join();
        cout<<"main end"<<endl;
        return 0;
    }

    5、成员函数指针做线程参数

    #include <iostream>
    #include <thread> //线程
    using namespace std;
    
    class A{
    public:
        int m_i;
        A(int a):m_i(a){cout << "A(int)构造函数执行了"<<"类对象的地址是:"<<this<<endl;}
        A(const A &a):m_i(a.m_i){cout<<"A(const)的拷贝构造函数执行了"<<endl;}
        ~A(){cout<<"A的析构函数执行"<<endl;}
    
        void thread_work(int num){
            //线程执行入口
            cout << "子线程开始"<<endl;
        }
    };
    
    int main(){
        A my(10);
        std::thread myobj(&A::thread_work,my,15);//注意成员函数参数写在后面,这时候的my已经是一个复制后的临时变量
        //thread myobj(&A::thread_work,&my,15)==(&A::thread_work,std::ref(my),15);这个时候就么有用拷贝构造函数,没有复制,用的就是my自己,此时不能用detach
        myobj.join();
        cout<<"main end"<<endl;
        return 0;
    }

    二、线程id

    线程id可以用c++获取到:std::this_thread::get_id()来获取。

    //在各自线程函数中:
    cout << std::this_thread::get_id()<<endl;

    坑以及注意事项

    传递指针时是浅拷贝,即使线程函数定义时是引用,引用的只是副本而已。

    主线程与子线程指针指向的同一内存,这样的情况很危险,多个指针指向同一个内存地址,子线程对这个内存对象的更改会影响到主线程中其他指针的使用。

    在 C++中,数组永远不会按值传递,它是传递第一个元素,准确地说是第 0个 的指针。

    c++数组没有引用的规则,定义函数时不能用引用传递数组。string是类,string类对象可以被引用。

  • 相关阅读:
    iOS把经纬度反转为位置信息(街道名等)
    ubuntu+mongodb
    IE6下绝对定位的高度自适应
    用Waitn控制网页
    PHPCMS 模板修改
    ubuntu+apache2+mono+mvc3
    灵活强大的jquery分页,样式可自定义
    委托与事件概要笔记
    ubuntu+nodejs
    linux 学习day3
  • 原文地址:https://www.cnblogs.com/pacino12134/p/11228024.html
Copyright © 2020-2023  润新知