并发与多线程三:线程传参详解,detach大坑,成员函数做线程函数

#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <thread>

using namespace std;

class A
{
public:
    mutable int m_i;
    A(int a) :m_i(a) { cout << "构造函数执行" << this<<"threadid="<<std::this_thread::get_id()<<endl; }
    A(const A &a) :m_i(a.m_i) { cout << "拷贝构造函数执行" << this << "threadid=" << std::this_thread::get_id()<<endl; }
    ~A(){ cout << "析构函数执行" << this << "threadid=" << std::this_thread::get_id()<<endl; }
};
//void myprint(const int &i,char *pmybuf)////分析认为,i并不是mvar的引用,实际是值传递,那么我们认为,即便主线程detach了子线程,
//那么子线程中用i值任然是安全的,所以不推荐用引用,一定不能用指针,第二个保准有错,
//{
//    cout << i << endl;
//    cout << pmybuf << endl;
//    return;
//}
//void myprint(const int i, const string &pmybuf)
//{
//    cout << i << endl;
//    cout << pmybuf.c_str() << endl;
//    return;
//}

//void myprint(const int i, const A &pmybuf)
//{
//    cout << &pmybuf<< endl;//这里打印的是mybuf对象的地址
//    return;
//}

void myprint2(const A &pmybuf)
{
    pmybuf.m_i = 199;//发现我修改该值不会影响到main函数,因为myobj和pmybuf的地址不一样,所以采用std::ref
    cout << "子线程myprint2的参数地址是"<<&pmybuf<<"threadid="<< std::this_thread::get_id()<<endl;
    return;
}
int main()
{
    //一:传递临时对象作为线程参数
    //事实1.只要临时构造的A 类对象做为参数传递给线程,那么就一定能够在主线程执行完毕前把线程函数的第二个参数构建出来,从而确保几百年detach了,子线程也安全运行。
    //1.3总结:
    //a)若传递int这种简单类型参数,建议都是值传递,不要用引用。
    //b)如果传递类类形,避免隐式类型转换。全部都在创建线程这一行就构建出临时对象来,然后再函数参数里用引用来接,否则系统还会多构造一次对象。
    //终极结论,建议不适用detach,只使用join(),就不存在上述问题了。


    //二:临时对象作为线程参数继续讲
    //(2.1)线程id概念:id是个数字,每个线程(不管是主线程还是子线程)实际上都对应着一个数字,而且每个线程对应的这个数字都不同
    //线程id可以用c++标准库里的函数来获取。std::this_thread::get_id()来获取

    //(2.2)临时对象构造时机抓捕
    //三。传递类对象,智能指针作为线程参数
    //std::ref函数
    //int mvar = 1;
    //int &mvary = mvar;
    //char mybuf[] = "this is a test";
    ////thread mytobj(myprint, mvar, mybuf);//但是mybuf到底什么时候转成string。事实上存在,mybuf都被回收了(main函数执行完了)
    //                                    //系统才用mybuf去转string
    //thread mytobj(myprint, mvar, string(mybuf));//这里直接将mybuf转换成string对象,这是一个可以保证再线程中用肯定有效的对象

    //mytobj.join();//用join没有问题

    //int mvar = 1;
    //int mysecondpar = 12;
    ////thread mytobj(myprint, mvar, mysecondpar);//希望mysecondpar转成A类型对象传递给myprint的第二个参数,会有问题,原因跟上边一样
    //thread mytobj(myprint, mvar, A(mysecondpar));//这样就可以了,在创建线程的同时构造临时对象的方法传递参数是可行的
    //mytobj.join();//用join还是没问题


    //cout << "主线程id是" << std::this_thread::get_id() << endl;
    //int mvar = 1;
    ////thread mytobj(myprint2, mvar);//这种情况通过查看线程id发现隐式转换的对象是在子线程中构造出来,当detach时这是个问题。
    //thread mytobj(myprint2, A(mvar));//这种情况就是再主线程中构造对象了
    //mytobj.join();


    A myobj(10);
    thread mytobj(myprint2, std::ref(myobj));//使用了ref不会再调用拷贝构造函数单独拷贝出一个对象,自然myobj和pmybuf的地址就一致了
    //mytobj.detach();//
    cout << "i love china" << endl;
    return 0;

}

 

posted @ 2020-09-28 16:10  AI_ON  阅读(110)  评论(0)    收藏  举报