1 c++多线程创建和传参

什么是进程?

系统资源分配的最小单位。

什么是线程?

操作系统调度的最小单位,即程序执行的最小单位。

为什么需要多线程?

(1)加快程序执行速度和响应速度, 使得程序充分利用CPU资源。

(2)多个线程可以在同一时间并行执行,将一个任务分成多份,让多个线程执行,加快执行速度。比如for循环,可以分解成多个线程同时处理。

(3)相比进程,线程创建和销毁的成本更低.

(4)同一进程内线程间的切换比进程间的切换要快,尤其是用户级线程间的切换。

进程和线程之间的关系

(1)线程属于进程,一个进程可以拥有多个线程,每个线程执行不同的任务。

(2)每个进程都有一个主线程。

(3)一个进程中的所有线程,共享资源和进程空间(代码段、数据段、堆等),但每个线程有各自的栈空间和线程控制块。

(4)进程之间的资源是独立的。

(5)进程间切换时,需要交换整个地址空间,而线程之间切换时,只是切换线程的上下文环境。

线程的状态

 线程的状态反映了线程在其生命周期中的不同阶段

  • New(新创建)

        线程已被创建,但未开始执行。

  • Ready(就绪)或 Runnable(可运行)

        线程已经准备好运行,但未获得CPU资源,进入就绪队列,就等着运行了。

  • Running(运行)

        线程正在cpu上执行代码,就绪状态的线程获取了CPU资源。

  • Blocked(阻塞)或 Waiting(等待)

        条件不满足,进入阻塞状态,条件满足了进入就绪状态。线程因为某种原因(如等待I/O操作完成、等待获取锁、等待通知等)而暂停执行。线程不会消耗CPU资源,并且不能执行任何代码,直到阻塞的原因被消除(如I/O操作完成、锁被释放、收到通知等)。

  • Terminated(被终止)

        线程已经完成了任务,或者由于某种原因(如异常,返回)而退出。一旦线程终止,就不能再运行。

sleep: 等到睡眠时间到,会自动恢复到就绪态。

挂起:是把进程或线程挂在外存,需要执行时,再把它移到内存中。

阻塞: 在等待某种事件或者资源,一旦获得资源或者事件信息就自动转成就绪态。

线程创建和参数传递

值传递

#include<thread>
#include<iostream>
#include<vector>using namespace std;// 值传递
// 该函数复制传入的变量,即在子线程中修改该参数不会影响主线程的参数。
void (int num)
{num += 1;cout << "子线程id: " << this_thread::get_id()<< ", num: " << num<< endl;cout<<"child thread num memory address: "<< &num<<endl;
}int main(int argc, char* argv[]){int num = 10;//t1为新建//第一个参数为函数名,第二个参数为该函数的第一个参数,如果该函数有多个参数就依次写在后面。此时线程开始执行。thread t1(thread_func_1, num);std::this_thread::sleep_for(std::chrono::milliseconds(100)); //sleep 100mscout << "主线程id: " << this_thread::get_id() << endl;cout << "主线程中获取子线程id " << t1.get_id() << endl;cout<<"main thread num memory address: "<< &num<<", num = "<<num<<endl;t1.join(); //阻塞主线程, 直至子线程执行结束。return 0;
}

编译

 g++ main.cpp -o main -l pthread

运行

./main

执行结果如下:

子线程id: 140038849767168, num: 11
child thread num memory address: 0x7f5d55e51dac
主线程id: 140038867724096
主线程中获取子线程id 140038849767168
main thread num memory address: 0x7fffeef939d0, num = 10

子线程num=11, nun内存地址是0x7f5d55e51dac;主线程num=10, nun内存地址是 0x7fffeef939d0。说明子线程中修改参数的值,没有改变主线程中的值。 num被复制后传递到thread_func_1中。

引用传递

#include<thread>
#include<iostream>
#include<vector>using namespace std;//传递引用
//传递参数时,使用std::ref, 在子线程中修改该参数会影响主线程的参数。
void thread_func_1(int& num)
{num += 1;cout << "thread_func_1子线程id: " << this_thread::get_id()<< ", num: " << num<< endl;cout<<"child thread num memory address: "<< &num<<endl;
}int main(int argc, char* argv[]){int num = 10;thread t1(thread_func_1, std::ref(num));std::this_thread::sleep_for(std::chrono::milliseconds(100)); //sleep 100mscout << "主线程id: " << this_thread::get_id() << endl;cout << "主线程中获取子线程id " << t1.get_id() << endl;cout<< "main thread num memory address: "<< &num<<", num = "<<num<<endl;t1.join(); //阻塞主线程, 直至子线程执行结束。return 0;
}

编译

 g++ main.cpp -o main -l pthread

运行

./main

执行结果如下:

thread_func_1子线程id: 140508139726592, num: 11
child thread num memory address: 0x7fffa22eea90
主线程id: 140508157683520
主线程中获取子线程id 140508139726592
main thread num memory address: 0x7fffa22eea90, num = 11

子线程num=11, 主线程num=11,内存地址都是0x7fffa22eea90。说明子线程中修改参数num的值,主线程中num数值也改变了。创建线程传参时加上std::ref操作的才是同一块内存。

指针传递

#include<thread>
#include<iostream>
#include<vector>using namespace std;// 传递指针, 在子线程中修改该参数会影响主线程的参数。
void thread_func_1(int* p)
{*p = *p + 1;cout << "子线程id: " << this_thread::get_id() <<endl;cout<<"child thread num memory address: "<< p<< ", num = " << *p<<endl;
}int main(int argc, char* argv[]){int num = 10;thread t1(thread_func_1, &num);std::this_thread::sleep_for(std::chrono::milliseconds(100)); //sleep 100mscout << "主线程id: " << this_thread::get_id() << endl;cout<<"main thread num memory address: "<< &num<<", num = "<<num<<endl;t1.join(); //阻塞主线程, 直至子线程执行结束。return 0;
}

编译

 g++ main.cpp -o main -l pthread

运行

./main

执行结果如下:

 

子线程id: 140096623552256
child thread num memory address: 0x7ffed5c7ead0, num = 11
主线程id: 140096641509184
main thread num memory address: 0x7ffed5c7ead0, num = 11

子线程num=11, 主线程num=11,内存地址相同。说明子线程中修改参数num的值,主线程中num数值也改变了。子线程和主线程访问的是同一块内存,传递指针和引用效果是一样的。

 线程可调用对象

C++中可调用对象:函数指针、lambda表达式、bind对象、仿函数等

函数指针

上面介绍传递引用代码中,介绍的可调用对象thread_func_1是函数指针。

#include<thread>
#include<iostream>
#include<vector>using namespace std;// 值传递
// 该函数复制传入的变量,即在子线程中修改该参数不会影响主线程的参数。
void (int num)
{num += 1;cout << "子线程id: " << this_thread::get_id()<< endl;cout<<"child thread num memory address: "<< &num<< ", num = " << num<<endl;
}int main(int argc, char* argv[]){int num = 10;thread t1(thread_func_1, num);std::this_thread::sleep_for(std::chrono::milliseconds(100)); //sleep 100mscout << "主线程id: " << this_thread::get_id() << endl;cout<<"main thread num memory address: "<< &num<<", num = "<<num<<endl;t1.join(); //阻塞主线程, 直至子线程执行结束。return 0;
}

bind对象

#include<thread>
#include<iostream>
#include<vector>
#include <functional>using namespace std;void thread_function(int arg1, std::string arg2) {std::cout << "child thread bind arguments: " << arg1 << " " << arg2 << std::endl;
}int main(int argc, char* argv[]){// std::bind将函数与其参数一起进行绑定// std::placeholders::_1 参数占位符, 指定函数参数的位置auto fn = std::bind(thread_function, std::placeholders::_1, std::placeholders::_2);std::thread t2(fn, 1, "20");t2.join();return 0;
}

编译

 g++ main.cpp -o main -l pthread

运行

./main

执行结果如下:

child thread bind arguments: 1 20

Lambda表达式

#include<thread>
#include<iostream>
#include<vector>using namespace std;void thread_func_1(int arg1, int arg2){std::cout << "child thread arguments: " << arg1 << ", " << arg2 << std::endl;
}int main(int argc, char* argv[]){int arg1 = 3;int arg2 = 5;//lambda表达式std::thread t1([arg1, arg2](){thread_func_1(arg1, arg2);});t1.join();return 0;
}

输出结果: 

child thread arguments: 3, 5

 仿函数

#include<thread>
#include<iostream>
#include<vector>using namespace std;class MyClass{public:MyClass(){cout << "constructor" << endl;}void operator()(int num)   // 重载括号运算符{cout << "num " << num << endl;}};int main(int argc, char* argv[]){MyClass object;std::thread t1(object, 5);t1.join();return 0;
}

成员函数

#include<thread>
#include<iostream>
#include<vector>using namespace std;class MyClass{public:void test(){cout<<"member function"<<endl;}};int main(int argc, char* argv[]){MyClass object;//第一个参数为类成员函数,第二个为类对象std::thread t1(&MyClass::test, &object);if(t1.joinable()){t1.join();}return 0;
}

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

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

相关文章

【MySQL】(基础篇二) —— MySQL初始用

MySQL初始用 目录 MySQL初始用基本语法约定选择数据库查看数据库和表其它的SHOW 在Navicat中&#xff0c;大部分数据库管理相关的操作都可以通过图形界面完成&#xff0c;这个很简单&#xff0c;大家可以自行探索。虽然Navicat等图形化数据库管理工具为操作和管理数据库提供了非…

upload-labs-第五关

目录 第五关 1、构造.user.ini文件 2、构造一个一句话木马文件&#xff0c;后缀名为jpg 3、上传.user.ini文件后上传flag.jpg 4、上传成功后访问上传路径 第五关 原理&#xff1a; 这一关采用黑名单的方式进行过滤&#xff0c;不允许上传php、php3、.htaccess等这几类文件…

AB测试学习(附有相关代码)

目录 一、基本概念1. 定义2. 作用3. 原理 二、实验基本原则三、实验步骤四、实验步骤详解1. 确定实验目的2. 确定实验变量3. 实验指标设计3.1 实验指标类型&#xff08;按作用区分&#xff09;3.1.1 核心指标3.1.2 驱动指标&#xff08;跟踪指标&#xff09;3.1.3 护栏指标 3.2…

vue-router全部搞定(附源码)

源码下载链接&#xff08;先转存&#xff0c;后下载&#xff09;&#xff1a;https://pan.quark.cn/s/b0c6edd68c21 怎么用vue-cli搭建项目 我们固然可以用传统htmljs的方式来搭建vue项目&#xff0c;但是如果组件很多&#xff0c;就需要通过Vue.component的方式一个个去引入…

mathematica中针对三维图中的颜色和填充透明度进行指定

颜色指定使用的命令为&#xff1a;PlotStyle 填充的透明度使用的命令为&#xff1a;FillingStyle 示例代码&#xff1a; Clear["Global*"] Plot3D[{Sin[x^2 y], Sin[x^2 - y]}, {x, -2, 2}, {y, -2, 2}, PlotStyle -> {Directive[Red, Specularity[White, 100…

1.VMware软件的安装与虚拟机的创建

1. VMware软件的安装 1.1 为什么需要虚拟机 嵌入式Linux开发需要在Linux系统下运行&#xff0c;我们选择Ubuntu。   1、双系统安装     有问题&#xff0c;一次只能使用一个系统。Ubuntu基本只做编译用。双系统安装不能同时运行Windows和Linux。   2、虚拟机软件   …

Golang Context详解

文章目录 基本介绍context源码剖析Context接口emptyCtxcancelCtxtimerCtxvalueCtx context使用案例协程取消超时控制数据共享 基本介绍 基本介绍 在Go 1.7版本中引入了上下文&#xff08;context&#xff09;包&#xff0c;用于在并发编程中管理请求范围的数据、控制生命周期、…

k8s 1.28 搭建rabbitmq集群

1.环境 1.1 k8s 1.28 1.2 rabbit 3.8 1.3 工作空间default 1.4 注意&#xff0c;内存最好充足一点&#xff0c;因为我就两个节点一个master、一个node&#xff0c;起初我的node是8g&#xff0c;还剩3~4G&#xff0c;集群竟然一直起不来&#xff0c;后来将虚拟机内存扩大&#x…

数字孪生智慧水利:精准管理与智能决策的新时代

图扑数字孪生技术在智慧水利中的应用&#xff0c;通过虚拟模型与真实水利系统的无缝连接&#xff0c;实现对水资源和水利工程的全面监控和精细管理。实时数据采集与动态模拟提升了水利系统的预测和响应能力&#xff0c;从洪水预警到水质监测&#xff0c;数字孪生助力各项决策更…

【Meetup】探索Apache SeaTunnel的二次开发与实战案例

在数据科技快速演进的今天&#xff0c;业务场景的复杂化和数据量的激增&#xff0c;推动了大数据技术的迅速发展&#xff0c;在众多开源大数据处理工具中&#xff0c;Apache SeaTunnel以其强大的数据集成能力&#xff0c;成为众多企业的首选。 但随着应用深入&#xff0c;企业面…

Java_Map集合

认识Map集合 Map集合称为双列集合&#xff0c;格式&#xff1a;{key1value&#xff0c;key2value2,key3value3,…},一次需要存一对数据作为一个元素。 Map集合的每个元素“Keyvalue” 称为一个键值对/键值对对象/一个Entry对象&#xff0c;Map集合也被叫做“键值对集合” Map集…

ViT:2 理解CLIP

大模型技术论文不断&#xff0c;每个月总会新增上千篇。本专栏精选论文重点解读&#xff0c;主题还是围绕着行业实践和工程量产。若在某个环节出现卡点&#xff0c;可以回到大模型必备腔调或者LLM背后的基础模型新阅读。而最新科技&#xff08;Mamba,xLSTM,KAN&#xff09;则提…

简单介绍一下vim

简单介绍一下vim 一、vim是什么&#xff1f;二、vim的优点三、vi/vim的使用命令模式输入模式底线命令模式 四、vi/vim 按键说明&#xff08;一&#xff09;命令模式可用的光标移动、复制粘贴、搜索替换等移动光标的方法:搜索替换的方法删除、复制与贴上的方法 &#xff08;二&a…

Unity 集成 FMOD 音频管理插件 2.02

Unity 集成 FMOD 音频管理插件 2.02 3. 集成教程&#xff1a;3.1 设置Unity项目3.2 设置FMOD项目3.3 设置 FMOD for Unity3.4 添加声音&#xff1a;卡丁车引擎3.5 添加声音&#xff1a;氛围3.6 添加声音&#xff1a;音乐3.7 删除现有音频3.8 下一步 10. 脚本 API 参考10.1 基础…

linux的持续性学习

安装php 第一步&#xff1a;配置yum源 第二步&#xff1a;下载php。 yum install php php-gd php-fpm php-mysql -y 第三步&#xff1a;启动php。 systemctl start php-fpm 第四步&#xff1a;检查php是否启动 lsof -i :9000 计划任务 作用&am…

设计模式- 责任链模式(行为型)

责任链模式 责任链模式是一种行为模式&#xff0c;它为请求创建一个接收者对象的链&#xff0c;解耦了请求的发送者和接收者。责任链模式将多个处理器串联起来形成一条处理请求的链。 图解 角色 抽象处理者&#xff1a; 一个处理请求的接口&#xff0c;可以通过设置返回值的方…

SpringBootWeb 篇-深入了解 Redis 五种类型命令与如何在 Java 中操作 Redis

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 Redis 概述 1.1 Redis 下载与安装 2.0 Redis 数据类型 3.0 Redis 常见五种类型的命令 3.1 字符串操作命令 3.2 哈希操作命令 3.3 列表操作命令 3.4 集合操作命令 …

Webpack 从入门到精通-基础篇

一、webpack 简介 1.1 webpack 是什么 webpack 是一种前端资源构建工具&#xff0c;一个静态模块打包器(module bundler)。 在 webpack 看来, 前端的所有资源文件(js/json/css/img/less/...)都会作为模块处理。 它将根据模块的依赖关系进行静态分析&#xff0c;打包生成对应的…

【深度学习】【机器学习】支持向量机,网络入侵检测,KDD数据集

文章目录 环境加载数据归一化数据训练模型用测试数据集给出评估指标准确率召回率预测某个输入数据随便取一行数据加载训练好的SVM支持向量机模型并预测 全部数据和代码下载 环境 之前介绍过用深度学习做入侵检测&#xff0c;这篇用向量机。 环境Python3.10 requirements.txt…

Vuex3学习笔记

文章目录 1&#xff0c;入门案例辅助函数 2&#xff0c;mutations传参辅助函数 3&#xff0c;actions辅助函数 4&#xff0c;getters辅助函数 5&#xff0c;模块拆分6&#xff0c;访问子模块的state辅助函数 7&#xff0c;访问子模块的getters辅助函数 8&#xff0c;访问子模块…