2. C++使用Thread线程参数传递问题

news2025/1/12 22:49:32

1. 说明

在子线程函数中进行参数传递,实际上是Thread类的构造函数对传递的参数进行了拷贝,拷贝到线程独立的内存中,及时参数是引用的形式,也可以在新线程中进行访问,如果参数传递时的类型不一致,在线程的上下文中会对类型进行隐式类型转换。不过当传递的参数是指针类型时需要特别注意,可能会有问题,具体见下文。

2. 普通参数传递

如果在子线程中不需要对传递过来的参数进行更改操作,那么传递参数时正常传递就行,为避免误操作,可以使用const关键字进行修饰 :

#include <iostream>
using namespace std;

#include <thread>

void myprint(const string s)
{
    cout << s << endl; 
}

int main()
{
    string s = "xiaoming";

    thread mythread(myprint, s);

    mythread.join();

    std::cout << "主线程:"<<s<<endl;

    return 0;
}

3. 传递引用(使用ref)

如果想在子线程中修改主线程中传递过来的数据,需要使用**std::ref()**函数:

#include <iostream>
using namespace std;

#include <thread>

void myprint(string& s)
{
    
    s = "xiaohong......";
    cout <<"子线程:" << s << endl;
    
}

int main()
{
    string s = "xiaoming";

    thread mythread(myprint, ref(s));

    mythread.join();

    std::cout << "主线程:"<<s<<endl;

    return 0;
}

4. 传递指针变量

Thread类虽然会对参数类型进行转换,但是遇到指针变量,还是需要进行显式类型转换,否则会出现问题。
悬垂指针:当所指向的对象被释放或者收回,但是对该指针没有作任何的修改,以至于该指针仍旧指向已经回收的内存地址,此情况下该指针便称悬垂指针

#include <iostream>
using namespace std;

#include <thread>

void myprint(const string& mbuffer)
{
    cout <<"子线程:" << mbuffer << endl;
}

int main()
{
    char buffer[] = "this is a test....";

    thread mythread(myprint,string(buffer));//使用string进行显式类型转换,避免悬垂指针

    mythread.join();

    std::cout << "主线程:运行结束...."<<endl;

    return 0;
}

4. 传递自定义的类

在自定义类中使用关键字mutable定义了一个变量,可以方便更改操作。实际将自定义类对象传输到子线程中,Thread构造函数会调用自定义类的拷贝构造函数,实际传输到子线程的类并非主线程中的原始类对象:

#include <iostream>
using namespace std;

#include <thread>

class A
{
public:
    A(int a) :m_i(a)
    {
        cout << "[A::A(int a )构造函数执行]" << this << "threadid = " << this_thread::get_id() << endl;
    }
    A(const A& a) :m_i(a.m_i)
    {
        cout << "[A::A(const a )拷贝构造函数执行]" << this << "threadid = " << this_thread::get_id() << endl;
    }
    ~A()
    {
        cout << "[A::~A( )析构函数执行]" << this << "threadid = " << this_thread::get_id() << endl;
    }
public:
    mutable int m_i;
};

void myprint(const A& a)//这里虽然使用了引用&,但输出结果发现并非是真正的引用,实际上引用的是拷贝构造函数复制出来的另一份对象a
{
    a.m_i = 2;//对变量进行更改
    cout <<"子线程入口函数(类中的变量):" << a.m_i << endl;
}


int main()
{
    int mvar = 1;

    A a(mvar);

    thread mythread(myprint,a);

    mythread.join();

    cout << "主线程(类中的变量):" << a.m_i << endl;//输出原始类对象中的m_i变量

    std::cout << "主线程:运行结束...."<<endl;

    return 0;
}

运行结果如下:发现两次输出的m_i的变量值是不一样的,而且类A的拷贝构造函数执行了
在这里插入图片描述
若想做到对自定义类真正的引用,需要使用std::ref()函数
修改上述代码如下:

thread mythread(myprint,std::ref(a));//传递参数时使用 ref 函数才能做到整正的引用

此时再输出结果会发现:并未调用自定义类中的拷贝构造函数
在这里插入图片描述

5. 传递自定义的类成员函数

注意使用引用的方式进行参数传递

#include <iostream>
using namespace std;

#include <thread>

class A
{
public:
    A(int a) :m_i(a)
    {
        cout << "[A::A(int a )构造函数执行]" << this << "threadid = " << this_thread::get_id() << endl;
    }
    A(const A& a) :m_i(a.m_i)
    {
        cout << "[A::A(const a )拷贝构造函数执行]" << this << "threadid = " << this_thread::get_id() << endl;
    }
    ~A()
    {
        cout << "[A::~A( )析构函数执行]" << this << "threadid = " << this_thread::get_id() << endl;
    }
    //添加成员函数
    void thread_work(int num)
    {
        cout << "[成员函数thread_work执行了....]" << endl;
    }

public:
    mutable int m_i;
};

void myprint(const A& a)
{
    a.m_i = 2;//对变量进行更改
    cout <<"子线程入口函数(类中的变量):" << a.m_i << endl;
    
}


int main()
{
    int mvar = 1;

    A myobj(mvar);

    //第一个参数是成员函数名,第二个参数是类对象名(注意使用引用的方式),第三个参数是成员函数需要的参数
    thread mythread(&A::thread_work,&myobj,15);

    mythread.join();

    std::cout << "主线程:运行结束...."<<endl;

    return 0;
}

6. 传递智能指针(使用std::move()函数)

#include <iostream>
using namespace std;

#include <thread>

void myprint(unique_ptr<int> pzn)
{
    
}

int main()
{
    unique_ptr<int> mypzn(new int(100));

    thread mythread(myprint,std::move(mypzn));

    mythread.join();

    std::cout << "主线程:运行结束...."<<endl;

    return 0;
}

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

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

相关文章

Servlet(二)

目录 1.Cookie 和 Session 1.1HttpServletRequest 类中的相关方法 1.HttpSession getSession() 2.Cookie[] getCookies() 1.2HttpServletResponse 类中的相关方法 1.void addCookie(Cookie cookie) 1.3HttpSession 类中的相关方法 1.4Cookie 类中的相关方法 1.5网页登录…

详解Spring Security

目录 1.概述 2.登录 2.1.默认用户 2.2.自定义用户 2.3.加密 2.4.绕过加密 2.5.怎么传递用户信息 2.6.记住我 3.登出 4.使用数据库 4.1.jdbcAuthentication 4.2.userDetailsService 5.自定义处理器 6.更多细粒度的控制 7.原理简述 1.概述 Spring Security是一个…

使用 Kubernetes 运行 non-root .NET 容器

翻译自 Richard Lander 的博客 Rootless 或 non-root Linux 容器一直是 .NET 容器团队最需要的功能。我们最近宣布了所有 .NET 8 容器镜像都可以通过一行代码配置为 non-root 用户。今天的文章将介绍如何使用 Kubernetes 处理 non-root 托管。 您可以尝试使用我们的 non-root…

gateway报 netty堆外内存溢出问题解决io.netty.util.internal.OutOfDirectMemoryError

昨天线上网关突然无法访问。打开日志看到错误信息“io.netty.util.internal.OutOfDirectMemoryError” 堆外内存溢出。。这也没碰到过啊&#xff0c;看来今天准点下班的愿望又落空了。老规矩面向百度编程。先看看网上有没有其他兄弟碰到这个问题。一顿搜索之后发现&#xff0c;…

已解决windows pycocotools安装失败问题 —— 超简单

作者主页&#xff1a;爱笑的男孩。的博客_CSDN博客-深度学习,YOLO,活动领域博主爱笑的男孩。擅长深度学习,YOLO,活动,等方面的知识,爱笑的男孩。关注算法,python,计算机视觉,图像处理,深度学习,pytorch,神经网络,opencv领域.https://blog.csdn.net/Code_and516?typecollect个人…

分库分表与分布式主键生成策略详解--一个无数人踩过却一直被人忽视的深坑

文章目录 一、从分库分表的一个神坑说起二、分布式主键要考虑哪些问题&#xff1f;三、主要的主键生成策略1、数据库策略2、应用单独生成3、第三方服务统一生成4、与第三方结合的segment策略 四、定制雪花算法1、如影随形的时钟回拨问题2、用主键生成策略优化分配工作进程位3、…

萤石“小步快走”,跨进智能家居生态圈

文丨智能相对论 作者丨Kinki 近日&#xff0c;萤石网络&#xff08;下称“萤石”&#xff09;举办了2023春季新品发布会&#xff0c;这是公司上市以来的首个新品发布会&#xff0c;除了拳头产品智能家居摄像机之外&#xff0c;还有智能入户产品、TV Studio等十多款新品&#…

NC65 集团业务参数 GLS01参数值的默认值作用是什么?

NC65 集团业务参数 GLS01参数值的默认值作用是什么&#xff1f; 用在总账系统的所有账簿。如果设置的期间个数大于12&#xff0c;还得要求所查询的账表支持跨年查询&#xff0c;比如科目余额表&#xff0c;不支持跨年&#xff08;注意&#xff1a;这里说的不支持跨年是指余额为…

4.2.1朴素模式匹配算法

什么是字符串的模式匹配&#xff1a; 从这段字符串里面搜索内容&#xff0c;被搜索的字符串我们称之为主串。 也可能匹配不到 主串长度为n&#xff0c;模式串长度为m。 朴素模式匹配算法&#xff1a;将主串中所有长度为m的字串依次与模式串对比&#xff0c;直到找到一个完全匹…

【JavaEE】File、InputStream和OutputStream的使用

1.File 在计算机中目录结构如下&#xff1a; 而File就表示一个目录或者一个普通文件。 File表示目录&#xff1a; File表示普通文件&#xff1a; 我们先来看File的构造方法&#xff1a; 构造器描述File(File parent, String child)根据父目录 孩子文件路径&#xff0c;创…

Linux权限提升—定时任务、环境变量、权限配置不当、数据库等提权

Linux权限提升—定时任务、环境变量、权限配置不当、数据库等提权 1. 前言1.1. 如何找编译好的EXP 2. 定时任务提权2.1. 查看定时任务2.2. 通配符注入提权2.2.1. 创建执行脚本2.2.2. 创建定时任务2.2.3. 查看效果2.2.4. 提权操作2.2.4.1. 切换普通用户2.2.4.2. 执行命令2.2.4.3…

优先、双端队列-我的基础算法刷题之路(八)

本篇博客旨在整理记录自已对优先队列、双端队列的一些总结&#xff0c;以及刷题的解题思路&#xff0c;同时希望可给小伙伴一些帮助。本人也是算法小白&#xff0c;水平有限&#xff0c;如果文章中有什么错误之处&#xff0c;希望小伙伴们可以在评论区指出来&#xff0c;共勉 &…

Netty 源码解析(下)

接上一篇博客 Netty 源码解析&#xff08;上&#xff09;继续分析 上一篇博客中已经分析了绝大部分 ChannelFuture cf bootstrap.bind(9000).sync(); 这一行代码&#xff0c;当这一行代码运行完时&#xff0c;Netty服务端就已经启动好了&#xff0c;接下来就是接收链接&#x…

Spring Security OAuth2.0(二)-----简化模式/密码模式/客户端模式/刷新 token

简化模式 代码示例 修改authorization_server授权服务模块 新增“implicit” 和修改回调地址为本次地址 修改第三方应用项目搭建新页面模拟 新建implicit.jsp <% page contentType"text/html;charsetUTF-8" language"java" isELIgnored"fals…

C++入门篇(二)

目录 一、引用1.1 什么是引用&#xff1f;1.2 引用的特性1.3 常引用1.4 引用的使用场景1.5 传值和传引用效率比较1.5.1 传值和传引用做参数的性能对比1.5.2 传值和传引用做返回值的性能对比 1.6 引用和指针之间的区别 二、内联函数2.1 什么是内联函数&#xff1f;2.2 内联函数的…

知识变现海哥|研究了100个项目,这个才是人生逆袭首选

&#xff08;本文源自公号跟海哥学知识变现&#xff0c;移步公号与100万知识变现/知识付费创业者&#xff0c;一起学知识变现知识付费干货&#xff0c;回‘领书’获取3本电子书&#xff1a;【知识付费秘籍】【知识创业者成长手册】【100个知识付费成功案例】) 经常有人问海哥&a…

什么是中断向量表?作用是什么?为什么需要偏移?

一、定义与特点 定义&#xff1a;中断向量表(interrupt vector table)包含中断服务程序地址的特定内存区域&#xff0c;这些服务程序是处理外部硬件中断请求的代码。 特点&#xff1a;这些中断服务程序(函数)在中断向量表中的位置是由半导体厂商定好的&#xff0c;当某个中断…

ESP32-C2开发板 Homekit烧录教程

准备 1.1硬件ESP32 C2开发板&#xff0c;如图1-1所示 图1-1 ESP32 C2开发板 1.2软件 CozyLife APP可以在各大应用市场搜索下载&#xff0c;也可以扫描二维码下载如图1-2所示 HomeKit flash download tool 烧录工具 esp32c2 homkit演示固件 烧录教程 打开flash_download_to…

以智求治,MapGIS打造公共安全治理新模式

随着我国城市人口和规模日益扩大&#xff0c;城市运行系统日趋复杂&#xff0c;各类风险隐患增多且呈现相互叠加、相互耦合态势&#xff0c;各类风险、事故灾害类事件造成的损失严重&#xff0c;公共安全防范压力不断增大。 党的二十大报告中指出&#xff1a;“建立大安全大应…

【容器化应用程序设计和开发】2.1 容器化基础知识和Docker容器

往期回顾&#xff1a; 第一章&#xff1a;【云原生概念和技术】 容器化应用程序设计和开发 2.1 容器化基础知识和Docker容器2.1.1 容器的创建2.1.2 容器的管理 容器化应用程序设计和开发是一种基于容器技术的应用程序设计和开发方法论。它将应用程序拆分为多个小型服务&#x…