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;
}
相关文章:

C++11并发与多线程笔记(3)线程传参详解,detach()大坑,成员函数做线程函数
C11并发与多线程笔记(3)线程传参详解,detach 大坑,成员函数做线程函数 1、传递临时对象作为线程参数1.1 要避免的陷阱11.2 要避免的陷阱21.3 总结 2、临时对象作为线程参数2.1 线程id概念2.2 临时对象构造时机抓捕 3、传递类对象…...

说几个常见的语法糖
目录 面试回答 知识扩展 如何解语法糖? 糖块一、swith 支持 String 与枚举 糖块二、泛型 糖块三、自动装箱与拆箱 糖块四、枚举 糖块五、条件编译 糖块六、断言 糖块七、数值字面量 糖块八、for-each 糖块九、try-with-resource 可能遇到的坑 泛型 自…...

Python文件操作与输入输出:从基础到高级应用
文章目录 🍀引言🍀文件操作基础🍀上下文管理器与文件自动关闭🍀文件的迭代与逐行读取🍀文件的其他常见操作🍀输入输出基础🍀 文件输入输出🍀格式化输出🍀高级文件操作&am…...

leetcode算法题--找出最安全路径
原题链接:https://leetcode.cn/problems/find-the-safest-path-in-a-grid/description/ func maximumSafenessFactor(grid [][]int) int {n : len(grid)type pair struct {x inty int}p : make([]pair, 0)dis : make([][]int, n)for i : range dis {dis[i] make([…...

神经网络基础-神经网络补充概念-34-正则化
概念 正则化是一种用于控制模型复杂度并防止过拟合的技术,在机器学习和深度学习中广泛应用。它通过在损失函数中添加一项惩罚项来限制模型的参数,从而使模型更倾向于选择简单的参数配置。 理解 L1 正则化(L1 Regularization)&a…...

idea打jar包
目录 1、打包设置 2、打包介绍 3、开始打包 1、打包设置 先设置要打包的模块信息,即打包进去的内容。如下图所示:File --> Project Structure --> Artifacts,点击+号完成模块创建,其中有两种方式:…...

民安汇智(第三方旅游服务暗访)开展旅游景区度假区明察暗访复核检查服务
近日,民安汇智受客户委托对该市某旅游景区度假区进行明察暗访复核检查工作。 民安汇智通过实地调研、体验式暗访等各种方式对该市范围内3A级以上旅游景区、旅游度假区及2022年新创建的3A级以上旅游景区、旅游度假区进行明察暗访复核检查,对照《旅游景区…...

《游戏编程模式》学习笔记(六)单例模式 Singleton Pattern
单例模式的定义 保证一个类只有一个实例,并且提供了访问该实例的全局访问点。 定义这种东西一般都是不说人话的,要想要理解这句话的意思,我们得把它揉开了才能搞明白。 我们先看前半句 “保证一个类只有一个实例”,单例一般使用…...

《Go 语言第一课》课程学习笔记(二)
初窥门径:一个 Go 程序的结构是怎样的? 创建“hello,world”示例程序 在 Go 语言中编写一个可以打印出“hello,world”的示例程序,我们只需要简单两步,一是创建文件夹,二是开始编写和运行。通…...

神经网络基础-神经网络补充概念-26-前向和反向传播
简单比较 前向传播(Forward Propagation): 前向传播是神经网络中的正向计算过程,用于从输入数据开始,逐层计算每个神经元的输出值,直到得到最终的预测值。在前向传播过程中,我们按以下步骤进行…...

Gin路由组
Gin路由组 文章目录 Gin路由组接收任意请求的路由接收没有被定义的路由路由组完整代码 接收任意请求的路由 区别于以往的GET()函数只能处理一种请求,Any()函数可以处理各种函数 语法: func (group *RouterGroup) Any(relativePath string, handlers ...HandlerFunc){} 案例: …...

安防监控视频云存储平台EasyNVR通道频繁离线的原因排查与解决
安防视频监控汇聚EasyNVR视频集中存储平台,是基于RTSP/Onvif协议的安防视频平台,可支持将接入的视频流进行全平台、全终端分发,分发的视频流包括RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、WebRTC等格式。为了满足用户的集成与二次开发需求…...

Redis-分布式锁!
分布式锁,顾名思义,分布式锁就是分布式场景下的锁,比如多台不同机器上的进程,去竞争同一项资源,就是分布式锁。 分布式锁特性 互斥性:锁的目的是获取资源的使用权,所以只让一个竞争者持有锁,这…...

Unity如何把游戏导出成手机安装包
文章目录 前言使用环境步骤添加场景构建APK 前言 本文章主要演示了,如何将制作好的游戏,导出成APK,安装到手机上。 使用环境 Unity2022。 步骤 首先打开你的项目,然后选择菜单栏的“File” > “Build Settings…”…...

使用爱校对软件保证公文材料质量的关键步骤
在日常的公文处理中,保证材料质量是每个企业和机构都追求的目标。而要实现这个目标,使用正确的工具是关键。爱校对软件正是这样一款专业的校对工具,它可以帮助我们保证公文材料的质量。接下来,让我们一起来看看使用爱校对软件保证…...

Spring Data Elasticsearch 的简单使用
目录 一、简介 二、配置 三、映射 四、 常用方法 五、操作(重点) 1、对索引表的操作 2、对文档的操作(重点) (1)、添加文档 (2)、删除文档 (3)、查询…...

2024」预备研究生mem-角平分线定理中线定理垂线定理、射影定理
一、角平分线定理 二、中线定理 三、垂线定理、射影定理 垂线定理 射影定理: 四、课后题...

nginx部署时http接口正常,ws接口404
可以这么配置 map $http_upgrade $connection_upgrade {default upgrade; close; }upstream wsbackend{server ip1:port1;server ip2:port2;keepalive 1000; }server {listen 20038;location /{ proxy_http_version 1.1;proxy_pass http://wsbackend;proxy_redirect off;proxy…...

数学建模的概念和学习方法(什么是数学建模)
一、初步认识数学建模 数学建模是将数学方法和技巧应用于实际问题的过程。它涉及使用数学模型来描述和分析现实世界中的现象、系统或过程,并通过数学分析和计算来预测、优化或解决问题。数学建模可以应用于各种领域,包括自然科学、工程、经济学、环境科学…...

ChatGPT在智能安全监测和入侵检测中的应用如何?
ChatGPT在智能安全监测和入侵检测领域具有潜在的应用价值。虽然ChatGPT主要是一个基于自然语言处理的模型,但结合其他技术和领域专业知识,它可以用于生成和分析文本数据,提供实时安全警报、威胁情报等,从而在安全监测和入侵检测方…...

智能数据建模软件DTEmpower 2023R2新版本功能介绍
DTEmpower是由天洑软件自主研发的一款通用的智能数据建模软件,致力于帮助工程师及工科专业学生,利用工业领域中的仿真、试验、测量等各类数据进行挖掘分析,建立高质量的数据模型,实现快速设计评估、实时仿真预测、系统参数预警、设…...

BDA初级分析——认识SQL,认识基础语法
一、认识SQL SQL作为实用技能,热度高、应用广泛 在对数据分析人员的调查中SQL长期作为热度排名第-一的编程语言超过Python和R SQL:易学易用,高效强大的语言 SQL:Structured Query Language 结构化查询语言 SQL:易学…...

Qt应用开发(基础篇)——MDI窗口 QMdiArea QMdiSubWindow
一、前言 QMdiArea类继承于QAbstractScrollArea,QAbstractScrollArea继承于QFrame,是Qt用来显示MDI窗口的部件。 滚屏区域基类 QAbstractScrollAreahttps://blog.csdn.net/u014491932/article/details/132245486 框架类 QFramehttps://blog.csdn.net/u01…...

图片转换成pdf格式?这几种转换格式方法了解一下
图片转换成pdf格式?将图片转换成PDF格式的好处有很多。首先,PDF格式具有通用性,可以在几乎任何设备上查看。其次,PDF格式可以更好地保护文件,防止被篡改或者复制。此外,PDF格式还可以更好地压缩文件大小&am…...

thingsboard编译安装踩坑记录
thingsboard编译安装踩坑记录 一、编译:二、运行 朋友的thingsboard没人维护,要装新的服务器,啥文档也没有,就让参考官网的文档,版本也比较老3.2.2的,拿过来试了试记录下踩坑的地方。 一、编译:…...

汇编语言例子集合
本人早酷爱汇编语言,曾经以自己能直接执行和操作机器码而自豪不已。下面列出一些电脑隐藏角落里的汇编语言例子程序。后续发现整理后会进一步添加完善。 汇编语言在windows上的bmp文件浏览器。 使用win32汇编编写。 下载地址:https://download.csdn.net/…...

强化学习:用Python训练一个简单的机器人
一、介绍 强化学习(RL)是一个令人兴奋的研究领域,它使机器能够通过与环境的交互来学习。在这篇博客中,我们将深入到RL的世界,并探索如何使用Python训练一个简单的机器人。在本文结束时,您将对 RL 概念有基本…...

【Docker】Docker使用之容器技术发展史
🎬 博客主页:博主链接 🎥 本文由 M malloc 原创,首发于 CSDN🙉 🎄 学习专栏推荐:LeetCode刷题集 🏅 欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正࿰…...

postgresql的在windows下的安装
postgresql的在windows下的安装 下载安装步骤超级用户设置密码本地化设置安装信息安装完成 查看postgresql服务pgAdmin的使用打开命令 行工具查询数据库版本 创建数据库 下载 官网地址 https://www.postgresql.org/ 下载页面 https://www.postgresql.org/download/ windows下…...

python 自动化学习(四) pyppeteer 浏览器操作自动化
背景 之前我在工作中涉及到了很多地方都是重复性的页面点点点工作,又因为安全保密原则不开放接口和数据库,只有一个页面来提供点击进行操作,就想着用前面学的自动化来实现,但发现前面学的模拟操作对浏览器来说并没有那么友好&…...