1.传递临时对象作为线程参数

  • 原始的输入程序如下:

    #include <iostream>
    #include <thread>using namespace std;void myprint(const int& i, char* pmybuf)
    {cout << i << endl;cout << pmybuf << endl;return;
    }int main(){int mvar = 1;int &mvary = mvar;char mybuf[] = "this is a test!";thread mytobj(myprint, mvar, mybuf);mytobj.join();cout << "I Love China!" << endl;return 0;
    }
    

1.1 要避免的陷阱1

  • 修改后的程序如下:
#include <iostream>
#include <thread>using namespace std;void myprint(const int& i, char* pmybuf)
{cout << i << endl; // 分析认为,i并不是mvar的引用,实际是值传递,那么我们认为,即使主线程detach了子线程,那么子线程中用i值仍然是安全的!cout << pmybuf << endl;  //  指针在detach子线程时,绝对会有问题!return;
}int main(){int mvar = 1;int &mvary = mvar;char mybuf[] = "this is a test!";thread mytobj(myprint, mvar, mybuf);mytobj.detach();  // 子线程和主线程分别执行!cout << "I Love China!" << endl;return 0;
}

  • 修改上述程序

    #include <iostream>
    #include <thread>
    #include <string>using namespace std;void myprint(const int i, const string& pmybuf)
    {cout << i << endl; cout << pmybuf.c_str() << endl; return;
    }int main(){int mvar = 1;int &mvary = mvar;char mybuf[] = "this is a test!";thread mytobj(myprint, mvar, mybuf);mytobj.detach();cout << "I Love China!" << endl;return 0;
    }
    

1.2 要避免的陷阱2

  • 但是,mybuf到底是在什么时候转换成string的?
#include <iostream>
#include <thread>
#include <string>using namespace std;void myprint(const int i, const string& pmybuf)
{cout << i << endl; cout << pmybuf.c_str() << endl; return;
}int main(){int mvar = 1;int &mvary = mvar;char mybuf[] = "this is a test!";thread mytobj(myprint, mvar, mybuf); // 但是mybuf到底是在什么时候转换成string的?mytobj.detach();cout << "I Love China!" << endl;return 0;
}
  • 结论:事实上存在,mybuf都被回收了(main函数执行完了),系统才用mybuf去转string的可能性
  • 继续修改上面的代码,可以见下面的反例程序:
    #include <iostream>
    #include <thread>
    #include <string>using namespace std;void myprint(const int i, const string& pmybuf)
    {cout << i << endl; cout << pmybuf.c_str() << endl;return;
    }int main(){int mvar = 1;int &mvary = mvar;char mybuf[] = "this is a test!";thread mytobj(myprint, mvar, string(mybuf));  // 我们这里直接将mybuf转换成string对象,这是一个可以保证在线程中用肯定有效的对象!!!mytobj.detach();cout << "I Love China!" << endl;return 0;
    }
    
  • 解释上面修改的原因见下面的程序:
    #include <iostream>
    #include <thread>
    #include <string>using namespace std;class A
    {
    public:int m_i;// 类型转换构造函数,可以把一个int转换成一个类A对象A(int a) :m_i(a){cout << "A::A(int a)构造函数执行" << endl;}A(const A& a) : m_i(a.m_i){cout << "A::A(const A& a)拷贝构造函数执行" << endl;}~A(){cout << "A::~A()析构函数执行" << endl;}
    };void myprint(const int i, const A& pmybuf)
    {cout << &pmybuf << endl;  // 这里打印的是pmybuf对象的地址
    }int main(){int mvar = 1;int mysecondpar = 12;thread mytobj(myprint, mvar, mysecondpar);  // 我们是希望mysecondpar转成A类型对象传递给myprint的第二个参数mytobj.detach();cout << "I Love China!" << endl;return 0;
    }
    
  • thread mytobj(myprint, mvar, A(mysecondpar)),在创建线程的同时构造临时对象的方法传递参数是可行的
  • 只要用临时构造的A类对象传递给线程,那么就一定能够在主线程执行完毕前把线程函数的第二个参数构建出来,从而确保即使detach了,子线程也能安全运行了

1.3 总结

  • 总结1:如果传递int这种简单类型的参数,建议都是值传递,不要用引用,防止节外生枝!
  • 总结2:如果传递类对象,避免隐式类型转换。全部都在创建线程这一行就构建出临时对象来,然后在函数参数里用引用来接,否则系统还会多构造一次对象,浪费空间
  • 终极结论:建议不使用detach(),只使用join():这样就不存在局部变量失效导致线程对内存的非法引用问题。

2.临时对象作为线程参数后续

2.1 线程id概念

2.2 临时对象构造时间抓捕

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

4.用过成员函数指针做线程函数

第三节 线程传参详解、detach()大坑、成员函数做线程函数相关推荐

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

    文章目录 3.1 传递临时对象作为线程参数 3.1.1 要避免的陷阱(解释1) 3.1.2 要避免的陷阱(解释2) 3.1.3 总结 3.2 临时对象作为线程参数进一步详解 3.2.1 线程id概念 ...

  2. C++:多线程中的小白(3)线程传参详解

    (1)传递临时对象作为线程参数 (2)传递类对象智能指针作为线程参数 (3)用成员函数指针做线程函数 在实际工作中我们要创建的线程可能不止一个,比如说我们要创建10个,编号从0到9,这10个线程会根据 ...

  3. C#进阶系列——WebApi 接口参数不再困惑:传参详解

    看这边文章时的疑惑是:WebApi中的参数加了[FromBody],不知所以然,就百度了下,看到了以下文章,和大家分享下: 原文链接:http://www.cnblogs.com/landeanfen ...

  4. python可变参数_Python 的四种共享传参详解

    点击上方"Python数据之道",选择"星标公众号" 精品文章,第一时间送达 作者 | 杨仁聪 编辑 | Lemon 出品 | Python数据之道 本文来自公 ...

  5. WebApi 接口参数不再困惑:传参详解

    阅读目录 一.get请求 1.基础类型参数 2.实体作为参数 3.数组作为参数 4."怪异"的get请求 二.post请求 1.基础类型参数 2.实体作为参数 3.数组作为参数 4 ...

  6. 【转】C#进阶系列——WebApi 接口参数不再困惑:传参详解

    阅读目录 一.get请求 1.基础类型参数 2.实体作为参数 3.数组作为参数 4."怪异"的get请求 二.post请求 1.基础类型参数 2.实体作为参数 3.数组作为参数 4 ...

  7. Spring/Boot/Cloud系列知识:SpringMVC 传参详解(下)

    (接上文<Spring/Boot/Cloud系列知识:SpringMVC 传参详解(上)>) 2.3.通过@PathVariable注解基于URL匹配符接收请求传参 为了便于开发人员实现更 ...

  8. Vue路由传参详解(params 与 query)

    Vue路由传参详解(params 与 query) 前言: 路由传参分为 params 传参与 query 传参 params 传参类似于网络请求中的 post 请求,params 传过去的参数不会显 ...

  9. Springboot传参详解

    作者简介 作者名:编程界明世隐 简介:CSDN博客专家,从事软件开发多年,精通Java.JavaScript,博主也是从零开始一步步把学习成长.深知学习和积累的重要性,喜欢跟广大ADC一起打野升级,欢 ...

最新文章

  1. QPushButton 点击信号分析
  2. Boost:align overflow对齐溢出的测试程序
  3. ubuntu 破解mysql密码_Ubuntu下忘记MySQL root密码解决方法
  4. Linux学习笔记-grep的基本认识
  5. 剑指offer06:从尾到头打印链表
  6. 配色方案--构图必学
  7. 数据结构上机实践第五周项目1- 建立顺序栈算法库
  8. 打印为带边框的表格_会这些Excel打印技巧的人,2秒搞定别人大半天的工作!
  9. 同是4G标准,TD和FDD怎么区分?谁更快?
  10. 【算法与数据结构】——并查集
  11. 循迹避障小车制作第一篇(tb6612模块与降压模块的使用)
  12. android6.0 framework修改使用两个声卡
  13. 企业家的“智慧”和“仁人”
  14. 计算机 英语简历,2017计算机英文简历范文
  15. oracle 创建cdb,Oracle 12C -- 手动创建CDB
  16. java 移动目录_java 移动文件夹内的文件,从一个目录移动到另外一个目录
  17. Telegram Bot Api使用教程
  18. Python 爬虫实战(2)
  19. 一道笔试题(求质数乘积)
  20. SPI 通信协议 最详细解读!!!

热门文章

  1. HTML5新特性总结
  2. 正确配置Linux系统ulimit值的方法【转】
  3. Android UI开发详解之ActionBar .
  4. htmlspecialchars() improvements in PHP 5.4
  5. HDOJ-1062 Text Reverse
  6. 新装myeclispse8.6GA、@Override出错
  7. 秒懂上线必不可少的安全测试!
  8. 实战!聊聊如何解决MySQL深分页问题
  9. 拼多多面试|如何用 Redis 统计独立用户访问量?
  10. 1.4 w字,25 张图让你彻底掌握分布式事务原理