线程可以共享进程的内存空间,线程拥有自己独立内存。

  关于参数的传递,std::thread的构造函数只会单纯的复制传入的变量,特别需要注意的是传递引用时,传入的是值的副本,也就是说子线程中的修改影响不了主线程中的值。

值传递

  主线程中的值,被拷贝一份传到了子线程中。

 1 #include <iostream>2 #include <thread>3 4 using namespace std;5 6 void test(int ti, int tj)7 {8     cout << "子线程开始" << endl;9     //ti的内存地址0x0055f69c {4},tj的内存地址0x0055f6a0 {5}
10     cout << ti << " " << tj << endl;
11     cout << "子线程结束" << endl;
12     return;
13 }
14
15
16 int main()
17 {
18     cout << "主线程开始" << endl;
19     //i的内存地址0x001efdfc {4},j的内存地址0x001efdf0 {5}
20     int i = 4, j = 5;
21     thread t(test, i, j);
22     t.join();
23     cout << "主线程结束!" << endl;
24     return 0;
25 }

传引用

  从下面的运行结果,可以看出,即使是用引用来接收传的值,也是会将其拷贝一份到子线程的独立内存中,这一点与我们编写普通程序时不同。这是因为线程的创建属于函数式编程,所以为了传引用C++中才引入了std::ref()。关于std::ref()。

 1 #include <iostream>2 #include <thread>3 4 using namespace std;5 6 class A{7 public:8      int ai;9      A (int i): ai(i) { }
10 };
11
12 //这种情况必须在引用前加const,否则会出错。目前本人的觉得可能是因为临时对象具有常性
13 void test(const int &ti, const A &t)
14 {
15     cout << "子线程开始" << endl;
16     //ti的内存地址0x0126d2ec {4},t.ai的内存地址0x0126d2e8 {ai=5 }
17     cout << ti << " " << t.ai << endl;
18     cout << "子线程结束" << endl;
19     return;
20 }
21
22
23 int main()
24 {
25     cout << "主线程开始" << endl;
26     //i的内存地址0x010ff834 {4},a的内存地址0x010ff828 {ai=5 }
27     int i = 4;
28     A a = A(5);
29     thread t(test, i, a);
30     t.join();
31     cout << "主线程结束!" << endl;
32     return 0;
33 }

  那么如果我们真的需要像一般程序那样传递引用呢,即在子线程中的修改能够反映到主线程中。此时需要使用std::ref()但是注意如果我们会在子线中改变它,此时用于接收ref()的那个参数前不能加const。关于C++多线程中的参数传引用问题,我目前只是记住了这个现象,关于原理还需后期研究源码继续学习。

 1 #include <iostream>2 #include <thread>3 4 using namespace std;5 6 class A {7 public:8     int ai;9     A(int i) : ai(i) { }
10 };
11
12 //接收ref()的那个参数前不能加const,因为我们会改变那个值
13 void test(int& ti, const A& t)
14 {
15     cout << "子线程开始" << endl;
16     cout << ti << " " << t.ai << endl;
17     ti++;
18     cout << "子线程结束" << endl;
19     return;
20 }
21
22
23 int main()
24 {
25     cout << "主线程开始" << endl;
26     int i = 4;
27     A a = A(5);
28     thread t(test, ref(i), a);
29     t.join();
30     cout << "i改变:" << i << endl;
31     cout << "主线程结束!" << endl;
32     return 0;
33 }

  传入类对象时,使用引用来接收比用值接收更高效。

 1 #include <iostream>2 #include <thread>3 4 using namespace std;5 6 class A {7 public:8     int ai;9     A (int i) : ai(i)
10     {
11         cout << "构造" << this << endl;
12     }
13
14     A (const A& a) :ai(a.ai) {
15         cout << "拷贝构造" << this << endl;
16     }
17
18     ~A()
19     {
20         cout << "析构" << this << endl;
21     }
22 };
23
24 //void test(const A a)
25 void test(const A& a)
26 {
27     cout << "子线程开始" << endl;
28     cout << "子线程结束" << endl;
29     return;
30 }
31
32
33 int main()
34 {
35     cout << "主线程开始" << endl;
36     int i = 4;
37     thread t(test, A(i));
38     t.join();
39     cout << "主线程结束!" << endl;
40     return 0;
41 }

传指针

  从下面的运行结果,可以看出,主线程和子线程中的指针都是指向同一块内存。所以在这种情况下会有一个陷阱,如果使用detach(),则当主线程崩溃或者正常结束后,该块内存被回收,若此时子线程没有结束,那么子线程中指针的访问将未定义,程序会出错。

 1 #include <iostream>2 #include <thread>3 4 using namespace std;5 6 7 void test(char *p) 8 {9     cout << "子线程开始" << endl;
10     //0x004ffeb4 "hello"
11     cout << p << endl;
12     cout << "子线程结束" << endl;
13     return;
14 }
15
16
17 int main()
18 {
19     cout << "主线程开始" << endl;
20     //0x004ffeb4 "hello"
21     char s[] = "hello";
22     thread t(test, s);
23     t.join();
24     cout << "主线程结束!" << endl;
25     return 0;
26 }

传临时对象

  用临时变量作为实参时,会更高效,由于临时变量会隐式自动进行移动操作,这就减少了整体构造函数的调用次数。而一个命名变量的移动操作就需要std::move()。

 1 #include <iostream>2 #include <thread>3 4 using namespace std;5 6 class A {7 public:8     int ai;9     A (int i) : ai(i)
10     {
11         cout << "构造" << this << endl;
12     }
13
14     A (const A& a) :ai(a.ai) {
15         cout << "拷贝构造" << this << endl;
16     }
17
18     ~A()
19     {
20         cout << "析构" << this << endl;
21     }
22 };
23
24 void test(const A& a)
25 {
26     cout << "子线程开始" << endl;
27     cout << "子线程结束" << endl;
28     return;
29 }
30
31
32 int main()
33 {
34     cout << "主线程开始" << endl;
35     int i = 4;
36     thread t(test, A(i));
37     t.join();
38     cout << "主线程结束!" << endl;
39     return 0;
40 }

总结

  1、使用引用和指针是要注意;

  2、对于内置简单类型,建议传值;

  3、对于类对象,建议使用引用来接收,以为使用引用会只会构造两次,而传值会构造三次;

  4、在detach下要避免隐式转换,因为此时子线程可能还来不及转换主线程就结束了,应该在构造线程时,用参数构造一个临时对象传入。

c++中多线程传递参数原理分析相关推荐

  1. python默认参数举例_Python中的默认参数实例分析

    本文研究的主要是Python中的默认参数的相关内容,具体如下. 熟悉C++语言的可以知道,C++语言中的默认参数是写在函数声明中的,为语法糖,与函数的调用无关,是在函数调用的时候由编译器补齐参数然后进 ...

  2. JDK 中的 BIO 实现原理分析(二十)

    今天对JDK 中的 BIO 实现原理进行分析 一.简介 对比 Linux 上网络编程,我们会发现 JDK Socket 的编程逻辑是一模一样的.实际上也是这样,JDK 网络编程也没有做很多事,主要还是 ...

  3. python参数传递方法_深入理解python中函数传递参数是值传递还是引用传递

    python 的 深入理解python中函数传递参数是值传递还是引用传递 目前网络上大部分博客的结论都是这样的: Python不允许程序员选择采用传值还是传 引用.Python参数传递采用的肯定是&q ...

  4. c语言va_start函数,va_start和va_end,以及c语言中的可变参数原理

    FROM:http://www.cnblogs.com/hanyonglu/archive/2011/05/07/2039916.html 本文主要介绍va_start和va_end的使用及原理. 在 ...

  5. js中函数传递参数,究竟是值传递还是引用传递?

    记住真理: js函数传递参数,不管是简单数据类型,还是引用数据类型,都是值传递!! 下面是js红包书里面的例子: function setName(obj) { obj.name = "Ni ...

  6. 转载】JQuery中如何传递参数如click(),change()等具体实现

    转载地址:http://www.jb51.net/article/36249.htm 有个需求让两个select中option相互转换,这个作业就是给几个按钮添加click()事件接下来为大家介绍下如 ...

  7. Delphi 多线程传递参数的问题

    unit uThread;interfaceusesClasses;typeTh = class(TThread)private{ Private declarations }protectedpro ...

  8. 数据结构与算法之KMP算法中Next数组代码原理分析

    2019独角兽企业重金招聘Python工程师标准>>> 一.KMP算法之Next数组代码原理分析       1.Next数组定义 当模式匹配串T失配的时候,Next数组对应的元素指 ...

  9. Java-Java中的线程池原理分析及使用

    文章目录 概述 线程池的优点 线程池的实现原理 线程池的使用 创建线程池 向线程池中提交任务 关闭线程池 合理的配置线程池 线程池的监控 概述 我们在上篇博文 Java-多线程框架Executor解读 ...

最新文章

  1. java静态/动态成员变量、初始化块,父类/子类构造函数执行顺序问题
  2. redis sentinel哨兵模式集群搭建教程
  3. 使用 FRP 反向代理实现 Windows 远程连接
  4. 信度和效度 智商计算
  5. Topaz Video Enhance AI中文版
  6. 低差别序列:高维序列(Halton sequence)
  7. Vue+axios配置踩坑记录
  8. 创建第一个Django项目
  9. kubernetes mysql ip_弄明白kubernetes中的“三种IP”
  10. mooc_java 集合框架中 学生所选课程2MapHashMap
  11. function函数嵌套 matlab_Matlab函数进阶:使用匿名函数和内嵌函数处理多变量传递问题...
  12. ruby map, reduce, select, reject, group_by
  13. php磁力链播放源码,Bt种子转磁力链 PHP源码
  14. oracle 文平,ORACLE调优之 内存结构调优(摘自文平书)
  15. 《功夫熊猫》的人生启示
  16. java开发高薪工程师,Java开发工程师如何获得高薪
  17. 2016/7/4日-你若安好,便是晴天.
  18. 如果我恨一个人,我就领他到中关村买相机。
  19. x^n mod 1003(快速求解法)
  20. 笔记本英雄联盟界面服务器停止运行,关于LOL选完大区(主界面)后马上闪退的正确解决方法...

热门文章

  1. JAVA复习(CharSequence接口、RunTime类、System类、object类中的finalize())
  2. android 恢复短信 失败,解决安卓手机发送短信失败的方法
  3. daterangepicker java_日期选择插件Date Range Picker
  4. php js 防止重复提交表单,php如何防止form重复提交
  5. php 蓝奏网盘上传文件,蓝奏云_文件上传_API
  6. 初中人教版电子课本app_电子课本|2020秋 部编人教版初中历史七年级上册教材电子课本(高清更新可打印)...
  7. 这个陶瓷电阻烙铁架不错哦,最新一期的电子趣事分享给大家
  8. HDLBits答案(19)_Verilog有限状态机(6)
  9. html标签强制转换位置,王老师html零基础学习笔记第4课——样式初始化+类型转化...
  10. linux ftp 553,修复使用vsftp出错553 Could not create file的有效方法