C++11并发与多线程笔记(3)线程传参详解,detach()大坑,成员函数做线程函数

C++11并发与多线程笔记(3)线程传参详解,detach 大坑,成员函数做线程函数

  • 1、传递临时对象作为线程参数
    • 1.1 要避免的陷阱1
    • 1.2 要避免的陷阱2
    • 1.3 总结
  • 2、临时对象作为线程参数
    • 2.1 线程id概念
    • 2.2 临时对象构造时机抓捕
  • 3、传递类对象、智能指针作为线程参数
    • 3.1 类对象作为线程参数
    • 3.2 智能指针作为线程参数
  • 4、用成员函数指针做线程函数

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

1.1 要避免的陷阱1

#include <iostream>
#include <thread>
using namespace std;void myPrint(const int &i, char* pmybuf)
{//如果线程从主线程detach了//i不是mvar真正的引用,实际上值传递,即使主线程运行完毕了,子线程用i仍然是安全的,但仍不推荐传递引用//推荐改为const int icout << i << endl;//pmybuf还是指向原来的字符串,所以这么写是不安全的cout << pmybuf << endl;
}int main()
{int mvar = 1;int& mvary = mvar;char mybuf[] = "this is a test";thread myThread(myPrint, mvar, mybuf);//第一个参数是函数名,后两个参数是函数的参数myThread.join();//myThread.detach();cout << "Hello World!" << endl;
}

在使用detach时,不推荐引用传递,指针传递肯定有问题

1.2 要避免的陷阱2

#include <iostream>
#include <thread>
#include <string>
using namespace std;void myPrint(const int i, const string& pmybuf)
{cout << i << endl;cout << pmybuf << endl;
}int main()
{int mvar = 1;int& mvary = mvar;char mybuf[] = "this is a test";//如果detach了,这样仍然是不安全的//因为存在主线程运行完了,mybuf被回收了,系统采用mybuf隐式类型转换成string//推荐先创建一个临时对象thread myThread(myPrint, mvar, string(mybuf));就绝对安全了thread myThread01(myPrint, mvar, mybuf);//myThread01.join();myThread01.detach();cout << "I love China!" << endl;
}

在创建线程的同时构造临时对象的方法传递参数是可行的

1.3 总结

  • 如果传递int这种基本数据类型,推荐使用值传递,不要用引用
  • 如果传递类对象,避免使用隐式类型转换,全部都是创建线程这一行就创建出临时对象,然后在函数参数里,用引用来接,否则还会创建出一个对象
  • 终极结论:建议不使用detach,只使用join,这样就不存在局部变量失效导致线程对内存的非法引用问题。

2、临时对象作为线程参数

2.1 线程id概念

  • id是个数字,每个线程(不管是主线程还是子线程)实际上都对应着一个数字,而且每个线程对应的这个数字都不一样。
  • 线程id可以用C++标准库里的函数来获取。**std::this_thread::get_id()**来获取

2.2 临时对象构造时机抓捕

#include<iostream>
#include<thread>
using namespace std;
class A {
public:int m_a;A(int a) :m_a(a) {cout << "A(int a):m_a(a)构造函数执行" << this << "  线程id为:" <<this_thread::get_id << endl;}A(const A& a):m_a(a.m_a){cout << "A(const A& a):m_a(a.m_a)拷贝构造函数执行" << this <<"  线程id为:" << this_thread::get_id << endl;}~A() {cout << "~A() 析构函数执行" << this <<"  线程id为:" << this_thread::get_id << endl;}};
void myPrint(const int i, const A& pmybuf) {cout << i << endl;cout << pmybuf.m_a<< endl;
}
int main() {int mvar = 1;int myseconder = 12;cout<<"主线程id为:"<< this_thread::get_id() << endl;thread myThread01(myPrint, mvar, A(myseconder));myThread01.detach();cout << "hello world" << endl;
}

在这里插入图片描述

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

3.1 类对象作为线程参数

#include <iostream>
#include <thread>
using namespace std;class A {
public:mutable int m_i; //m_i即使实在const中也可以被修改A(int i) :m_i(i) {}
};void myPrint(const A& pmybuf)//虽然是参数引用,但还是没有修改主线程中m_i值
{pmybuf.m_i = 199;//修改的值不影响main函数cout << "子线程myPrint的参数地址是" << &pmybuf << "thread = " << std::this_thread::get_id() << endl;
}int main()
{A myObj(10);//myPrint(const A& pmybuf)中引用不能去掉,如果去掉会多创建一个对象//const也不能去掉,去掉会出错//即使是传递的const引用,但在子线程中还是会调用拷贝构造函数构造一个新的对象,//所以在子线程中修改m_i的值不会影响到主线程//如果希望子线程中修改m_i的值影响到主线程,可以用thread myThread(myPrint, std::ref(myObj));,省去了传递时的拷贝构造函数//这样const就是真的引用了,myPrint定义中的const就可以去掉了,类A定义中的mutable也可以去掉了thread myThread(myPrint, myObj);myThread.join();//myThread.detach();cout << "Hello World!" << endl;
}

分析:

  • void myPrint(const A& pmybuf)//虽然是参数引用(& pmybuf),但还是没有修改主线程中m_i值
  • 如果希望子线程中修改m_i的值影响到主线程,可以用thread myThread(myPrint, std::ref(myObj));

3.2 智能指针作为线程参数

#include <iostream>
#include <thread>
#include <memory>
using namespace std;void myPrint(unique_ptr<int> ptn)
{cout << "thread = " << std::this_thread::get_id() << endl;
}int main()
{unique_ptr<int> myp(new int(10));//独占式智能指针只能通过std::move()才可以传递给另一个指针//传递后up就指向空,新的ptn指向原来的内存//所以这时就不能用detach了,因为如果主线程先执行完,ptn指向的对象就被释放了thread myThread(myPrint, std::move(myp));myThread.join();//myThread.detach();return 0;
}

分析:

  • unique_ptr 构造函数已经将拷贝函数和拷贝赋值删除了,禁止拷贝,如果需要将unique_ptr对象传入,需要使用std::move(myp)

4、用成员函数指针做线程函数

class A {
public:int m_a;A(int a) :m_a(a) {cout << "A(int a):m_a(a)构造函数执行" << this << "  线程id为:" <<this_thread::get_id << endl;}A(const A& a):m_a(a.m_a){cout << "A(const A& a):m_a(a.m_a)拷贝构造函数执行" << this <<"  线程id为:" << this_thread::get_id << endl;}~A() {cout << "~A() 析构函数执行" << this <<"  线程id为:" << this_thread::get_id << endl;}void thread_work(int i) {cout << "子线程thread_work执行" << this <<"  thread_work线程id为:" << this_thread::get_id << endl;}void operator()(int i){cout << "子线程operator()执行" << this <<"  operator()线程id为:" << this_thread::get_id << endl;}
};int main() {cout<<"主线程id为:"<< this_thread::get_id() << endl;A myobj(10);//生成一个类对象;//参数1:传成员函数地址//参数2:对象名//参数3:函数所需的参数thread myThread(&A::thread_work,myobj,15)// &myobj==std::ref(myobj) 不调用拷贝构造函数了,那后续如果调用myThread就不安全了//thread myThread(myobj,15) //使用 operator()作为子线程入口myThread.detach();cout << "hello world" << endl;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/39144.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VR时代真的到来了?

业界对苹果的期待是&#xff0c;打造一台真正颠覆性的&#xff0c;给头显设备奠定发展逻辑底座的产品&#xff0c;而实际上&#xff0c;苹果只是发布了一台更强大的头显。 大众希望苹果回答的问题是“我为什么需要一台AR或者VR产品&#xff1f;”&#xff0c;但苹果回答的是“…

从零开始学习 Java:简单易懂的入门指南之MAth、System(十二)

常见API&#xff0c;MAth、System 1 Math类1.1 概述1.2 常见方法1.3 算法小题(质数)1.4 算法小题(自幂数) 2 System类2.1 概述2.2 常见方法 1 Math类 1.1 概述 tips&#xff1a;了解内容 查看API文档&#xff0c;我们可以看到API文档中关于Math类的定义如下&#xff1a; Math类…

每天一道leetcode:300. 最长递增子序列(动态规划中等)

今日份题目&#xff1a; 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组 [0,3,1,6,2,2,7] …

【JavaEE进阶】SpringBoot项目的创建

文章目录 一. SpringBoot简介1. 什么是SpringBoot?2. SpringBoot的优点 二. SpringBoot项目创建1. 使用IDEA创建2. 使用网页创建SpringBoot项目 三. 运行SpringBoot项目 一. SpringBoot简介 1. 什么是SpringBoot? Spring Boot 是一个用于快速构建基于 Spring 框架的应用程序…

Spring对象装配

在spring中&#xff0c;Bean的执行流程为启动spring容器&#xff0c;实例化bean&#xff0c;将bean注册到spring容器中&#xff0c;将bean装配到需要的类中。 既然我们需要将bea装配到需要的类中&#xff0c;那么如何实现呢&#xff1f;这篇文章&#xff0c;将来阐述一下如何实…

SOFABoot——基本使用(笔记)

文章目录 一、前言二、快速开始2.1 基本搭建2.2 测试是否成功2.3 其他部分日志测试异步启动 三、SOFABoot的模块化开发3.1 基于Spring上下文的隔离3.2 Root Application Context3.3 模块并行化启动3.4 JVM服务与RPC服务的发布与引用3.5 模块配置Module-NameRequire-ModuleSprin…

wsl2安装mysql环境

安装完mysql后通过如下命令启动mysql service mysql start 会显示如下错误&#xff1a; mysql: unrecognized service 实际上上面显示的错误是由于mysql没有启动成功造成的 我们要想办法成功启动mysql才可以 1.通过如下操作就可以跳过密码直接进入mysql环境 2.如果想找到my…

微服务与Nacos概述-5

引入OpenFeign 添加依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency><groupId>com.alibaba.cloud</groupId>…

“记账”很麻烦,看这场竞赛中的队伍与合合信息是如何解决问题的

在我们日常生活中或多或少都会有记账的情况&#xff0c;以此来对自己的收支和消费习惯进行分析&#xff0c;来帮助自己减少不必要的开支&#xff0c;优化财务决策、合理分配资金&#xff0c;减少财务压力和不必要的浪费。 但记账这个动作本身就是一件比较麻烦的。虽然现阶段有…

数据结构入门 — 时间复杂度、空间复杂度

前言 数据结构_空间复杂度_时间复杂度讲解_常见复杂度对比 本文介绍数据结构中的时间复杂度和空间复杂度 ***文章末尾&#xff0c;博主进行了概要总结&#xff0c;可以直接看总结部分*** 博主博客链接&#xff1a;https://blog.csdn.net/m0_74014525 点点关注&#xff0c;后期…

哈夫曼树(赫夫曼树、最优树)详解

目录 哈夫曼树&#xff08;赫夫曼树、最优树&#xff09;详解 哈夫曼树相关的几个名词 什么是哈夫曼树 构建哈夫曼树的过程 哈弗曼树中结点结构 构建哈弗曼树的算法实现 哈夫曼树&#xff08;赫夫曼树、最优树&#xff09;详解 哈夫曼树相关的几个名词 路径&#xff1a;…

实验三 图像分割与描述

一、实验目的&#xff1a; &#xff08;1&#xff09;进一步掌握图像处理工具Matlab&#xff0c;熟悉基于Matlab的图像处理函数。 &#xff08;2&#xff09;掌握图像分割方法&#xff0c;熟悉常用图像描述方法。 二、实验原理 1.肤色检测 肤色是人类皮肤重要特征之一&#xff…

7.原 型

7.1原型 【例如】 另外- this指向&#xff1a; 构造函数和原型对象中的this都指向实例化的对象 7.2 constructor属性 每个原型对象里面都有个constructor属性( constructor构造函数) 作用&#xff1a;该属性指向该原型对象的构造函数 使用场景: 如果有多个对象的方法&#…

Springboot 实践(4)swagger-ui 测试controller

前文项目操作&#xff0c;完成了项目的创建、数据源的配置以及数据库DAO程序的生成与配置。此文讲解利用swagger-ui界面&#xff0c;测试生成的数据库DAO程序。目前&#xff0c;项目swagger-ui界面如下&#xff1a; 以”用户管理”为例&#xff0c;简单讲述swagger-ui测试数据库…

无涯教程-Perl - s函数

描述 这不是功能。这是正则表达式替换运算符。根据PATTERN中指定的正则表达式,将数据替换为REPLACE。与m //一样,分隔符由s后的第一个字符定义。 语法 以下是此函数的简单语法- s/PATTERN/REPLACE/返回值 如果失败,此函数返回0,如果成功,则返回替换次数。 例 以下是显示…

【Python机器学习】实验10 支持向量机

文章目录 支持向量机实例1 线性可分的支持向量机1.1 数据读取1.2 准备训练数据1.3 实例化线性支持向量机1.4 可视化分析 实例2 核支持向量机2.1 读取数据集2.2 定义高斯核函数2.3 创建非线性的支持向量机2.4 可视化样本类别 实例3 如何选择最优的C和gamma3.1 读取数据3.2 利用数…

Open3D 最小二乘拟合平面(SVD分解法)

目录 一、算法原理二、代码实现三、结果展示1、点云2、拟合结果四、优秀博客本文由CSDN点云侠原创,原文链接。爬虫网站自重。 一、算法原理 本文实现矩阵奇异值分解方法的最小二乘拟合平面。原理如下: 对于得到的 n n

欧拉函数(质因子分解)

思路&#xff1a; (1)欧拉函数&#xff1a;输入n则输出1~n中与n互质的数的个数。 &#xff08;2&#xff09;计算公式&#xff1a; &#xff08;3&#xff09;证明&#xff1a;&#xff08;容斥原理&#xff09;对于n个数&#xff0c;先分别摘除所有被pi整除的数&#xff0c;…

亿信ABI有什么不同,来看最新DEMO演示

为了给用户营造更好的体验环境&#xff0c;提供更丰富、更完善的服务&#xff0c;亿信华辰旗下核心产品亿信ABI DEMO再次上新啦&#xff01;本次亿信ABI DEMO环境在原有基础上焕新升级&#xff0c;带来了全新的主视觉界面、丰富的行业应用和功能演示DEMO&#xff0c;我们一起来…

季度到季度的组件选择

组件&#xff1a;<template><div class"quarter"><div class"input-wrap" id"closeId" mouseover"handler" click.stop"btn" :style"{color:colorItem}"><i class"el-icon-date"&…