天天看点

三、线程传参

引用和指针:

陷进一:不要用引用和指针,因为地址可以被主线程运行完后释放了。

陷阱二:将对象传递给子线程时,可能主线程都运行完了,对象还没构建。

通过源码可知,thread类禁用了拷贝构造函数,但支持对象move

带参架构函数接受的值是右值引用。非带参和move的线程都是非joinable的。

指针变量如果用detach,很可能主线程结束了,子线程读取指针变量发生错误。

都是右值引用,为什么int安全,int*类型不安全:

主线程中的i=1和int *p在传参时应该都是传的临时值。

int* && pp=p后,其实最终访问的数据还是i,如果 i 释放了,那么p的副本pp也会访问失败。

int& i;由于子线程不接受左值,主线程会根据左值生成临时值,然后右值引用=临时值。

三、线程传参

  右值引用就是对临时对象的引用,右值引用在临时对象释放后,还是能更改右值引用所引用的值。下面的代码就是主线程负责申请临时空间,然后通过右值引用拿来用。

  string& pmybuf=string(mybuf):

  通过上面分析,首先得到 pmybuf 的副临时对象,然后把 pmybuf 副本转换为右值引用。就类似函数参数要求int ,但传过来的是double。

id是个数字,每个线程实际上都对应着一个数字,而且每个线程对应的数字都不同,也就是说不同的线程id必然是不同的;

线程id可以通过c++标准库里的函数来获取。std::this_thread::get_id().

thread类直接包装了一个pthread_t,在linux下实际是unsigned long int。

用了一个std::unique_ptr来包装用户定义的线程函数:

如果thread()中的参数不是线程函数需要的类对象,

运行结果:

三、线程传参

 由此可知,类型转换是在在线程中进行的(之前的分析也推出这个结论),那么久带来了一个问题:

  主线程已经吧var的临时对象给子线程了,但是子线程还没构造a对象(比如时间片还没轮到子线程),主线程久执行完了,那临时对象也肯定会销毁,这种情况就会导致程序异常。

  为什么不让子线程生成临时对象呢:也就是可能子线程的时间片还没到,没机会生成临时对象。(其实是我猜的)

修改代码:

三、线程传参

主线程:

   构造函数:将var转换成a类;拷贝构造:根据a生成a的临时对象;

子线程:

  const a& a=临时a对象后:const a& 可以接受左值引用也可以接受右值引用

 如果参数不用const a&,会调用两次a的拷贝构造函数,子线程会多调用一次拷贝构造函数。a a=临时a对象。

上面代码虽然传递的参数是引用,但是当它在子线程中执行时并不会影响主线程的变量。也就是说mybuf仍然是拷贝出来的,不是主线程传递对象的引用。

三、线程传参
三、线程传参

 在主线程中又执行了拷贝构造函数

增加std::ref()后 

三、线程传参
三、线程传参

心之所愿,永不相忘

继续阅读