• C++11多线程第三篇:线程传参详解,detach()大坑,成员函数做线程参数


    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    输出结果:

    10
    more thread
    main thread end
    PS C:\Users\Administrator\Desktop\thread\build\thread可执行对象传参陷阱\Debug>
    
    • 1
    • 2
    • 3
    • 4

    std::thread obj(myPrint,val,arr); //第一个参数传可执行对象,线程入口函数,后面传线程入口函数参数

    • 线程入口函数以及线程入口函数的参数实现时参数如果采用的是引用接收的话而不是真正的引用,也是值传递。所以当使用detach()主线程与子线程分开执行的时候也不影响,因为不是引用传递而是值传递,可以调试根据传递的参数地址对比就可以得出来。但推荐这里线程入口函数参数一般不加&。
    • 线程入口函数以及线程入口函数的参数实现时参数如果采用的是指针接收传递过来的数组或者对象的话这样是不可取的,因为指针指向的是数组的地址或者是对象的地址,指针地址和主线程中的参数地址一样。当采用的线程函数是detach()时候这是就会因为主线程先于子线程退出,那么主线程中的成员变量是局部变量那么被销毁的传参就会发生异常。
    3.1.2 要避免的陷阱(解释2)
    • 只要用临时构造的A类对象作为线程入口函数参数的第二个参数传递给线程,那么一定可以在主线程运行完毕之前把线程入口函数的第二个参数构建出来,从而确保detach()子线程安全运行,不发生异常。

    代码如下:

    #include
    #include
    
    
    class A{
    public:
        A(const int& a)
        :a_(a){
            std::cout<<"A的构造函数 "<
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    输出结果:

    A的拷贝构造
    A的析构函数
    10
    0000025EB5E71B50
    A的析构函数
    hhhh
    PS C:\Users\Administrator\Desktop\thread\build\thread可执行对象传参陷阱2\Debug>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    3.1.3 总结
    • 若传递int这种简单类型参数,建议都使用值传递,不要引用传递。防止节外生枝。

    • 如果传递的是类对象,避免隐式类型转换。全部都在创建线程这一行就构建出临时对象来,然后在函数参数里,用引用来接收对象,防止再一次发生拷贝构造影响内存效率。

    • 终极结论:

      • 建议不适用detach(),只使用join(),这样就不存在局部变量失效导致线程对内存的非法引用问题。

    3.2 临时对象作为线程参数进一步详解

    3.2.1 线程id概念
    • id是个数字,每个线程(不管是主线程还是子线程)实际上都对应着一个数字,而且每个线程对于的数字都不一样,也就是说,不同的线程,它的线程id(数字)必然是不同的。
    • 线程id可以是用C++标准库里的函数来获取。std::this_thread::get_id()来获取的。
    3.2.2 临时对象构造时机抓捕

    代码如下:

    #include
    #include
    
    class A{
    public:
        A(int a)
        :a_(a){
            std::cout<<"A的构造函数: "<

输出结果:

PS D:\C++11多线程代码编写\build\thread临时对象构造时机抓捕\Debug> .\main.exe
A的构造函数: 10 this指针地址:000000C378EFF984 主线程id:2100
A的拷贝函数: 10 this指针地址:0000022C4ECA3280 主线程id:2100
A的析构函数: 10 this指针地址:000000C378EFF984 主线程id:2100
子线程MyPrint函数的参数地址: 0000022C4ECA3280 线程id:13520
A的析构函数: 10 this指针地址:0000022C4ECA3280 主线程id:13520
主线程main函数的线程id:2100
PS D:\C++11多线程代码编写\build\thread临时对象构造时机抓捕\Debug>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

3.3 传递类对象、智能指针作为线程参数

3.3.1 传递类对象作为线程参数

代码如下:

#include
#include

class A{
public:
    A(int a)
    :a_(a){
        std::cout<<"A的构造函数: "<

输出结果:

A的构造函数: 10 this指针地址:000000F448EFFD84 主线程id:11712
A的拷贝函数: 10 this指针地址:0000024FE7102BC0 主线程id:11712
&val.a_的地址:0000024FE7102BC0
子线程MyPrint函数的参数地址: 0000024FE7102BC0 线程id:8836
A的析构函数: 100 this指针地址:0000024FE7102BC0 主线程id:8836
主线程main函数的线程id:11712
A的析构函数: 10 this指针地址:000000F448EFFD84 主线程id:11712
PS D:\C++11多线程代码编写\build\thread传递类对象、智能指针作为线程参数\Debug>

代码如下:

#include
#include

class A{
public:
    A(int a)
    :a_(a){
        std::cout<<"A的构造函数: "<

输出结果:

PS D:\C++11多线程代码编写\build\thread传递类对象、智能指针作为线程参数\Debug> .\main.exe 
A的构造函数: 10 this指针地址:0000002019B9F774 主线程id:11044
&val.a_的地址:0000002019B9F774
子线程MyPrint函数的参数地址: 0000002019B9F774 线程id:7904
主线程main函数的线程id:11044
A的析构函数: 100 this指针地址:0000002019B9F774 主线程id:11044
PS D:\C++11多线程代码编写\build\thread传递类对象、智能指针作为线程参数\Debug>
3.3.2 传递智能指针作为线程参数

代码如下:

#include
#include

class A{
public:
    A(int a)
    :a_(a){
        std::cout<<"A的构造函数: "< spa){
    std::cout<<*spa< sp(new int(10));
    // std::thread obj(MyPrint,std::ref(a));
    //std::thread obj(MyPrint,sp);
    std::cout<

输出结果:

0000004D7EAFF608
10
子线程MyPrint函数的参数地址: 0000004D7EEFF8A0 线程id:11876
0000004D7EAFF608
主线程main函数的线程id:15428
PS D:\C++11多线程代码编写\build\thread传递类对象、智能指针作为线程参数\Debug>

3.4 用类成员函数指针做线程参数

代码如下:

#include
#include

class A{
public:
    A(int a)
    :a_(a){
        std::cout<<"A的构造函数: "< spa){
    std::cout<<&spa< sp(new int(10));
    // std::thread obj(MyPrint,std::ref(a));
    //std::thread obj(MyPrint,sp);
    // std::cout<

输出结果:

PS D:\C++11多线程代码编写\build\thread用成员函数指针做线程参数\Debug> .\main.exe
A的构造函数: 10 this指针地址:000000617A10F734 主线程id:8504
A的拷贝函数: 10 this指针地址:000001C09F7D05E4 主线程id:8504
子线程成员函数执行 this指针地址:000001C09F7D05E4 子线程id:15448
A的析构函数: 10 this指针地址:000001C09F7D05E4 主线程id:15448
主线程main函数的线程id:8504
A的析构函数: 10 this指针地址:000000617A10F734 主线程id:8504
PS D:\C++11多线程代码编写\build\thread用成员函数指针做线程参数\Debug>     
  • 相关阅读:
    Java使用线程池
    【STA】(1)引言
    小白实操搭建Nginx1.2.0+PHP7.0+MySQL5.7+Thinkphp5项目,看这篇就够了
    Nginx 防盗链
    如何通过数据治理来提升业务价值——业务场景治理
    看了这篇文章CAP你还不懂,我打你!
    flex布局之美,以后就靠它来布局了
    Django——路由层
    Java:实现动态数组类算法(附完整源码)
    【Eclipse中的Preferences窗口中没有Server的解决方案】&【Eclipse配置Tomcat】
  • 原文地址:https://blog.csdn.net/qq_44918090/article/details/127838653