Cpp多线程(一)

一、基本概念

1、程序是一段静态代码;进程是正在运行的程序;线程则是程序内部的执行路径。

上面这张图就解释了线程和多线程的意义。

2、若一个程序在同一时间执行多个线程,便是支持多线程的。一个进程中的多个线程共享相同的内存单元/内存地址空间。

二、两种形式的多线程

1、单CPU内核的多线程

单个CPU以极高的频率轮流执行多个线程的运算,各个线程雨露均沾。

2、多CPU内核的多线程

可以做到真正的并行运算

所以,现在我们所说的软件意义上的线程和硬件意义上的线程(如我的i7就是4核心8线程)并不是同一个概念。单个CPU内核也可以模拟出多个线程。对于一般的家用电脑,运行大约100个线程是可行的。

三、Cpp的多线程

在C++11标准之前,C++多线程需要借助操作系统提供的API,如Linux的pthread.h库和Windows的<windows.h>库。C++11提供了语言层面上的多线程,包含在头文件<thread>中。它解决了跨平台的问题。以下的各个库均为C++11标准为多线程所设计的:

  1. thread
  2. mutex
  3. atomic
  4. condition_variable
  5. future 

四、创建线程

创建线程时,必须把需要分开执行的程序封装在不同的代码块里,也就是函数里。对于线程,C++用类来描述,创建了一个Thread类的对象,即是新增了一个线程。

比如说我要分别执行两个冒泡排序,我便先写了一个冒泡排序的函数。

void bubblesort(int* array,int len)
{for(int i=1;i<len;i++){for(int j=0;j<len-i;j++){if (array[j]>array[j+1]){int temp=array[j];array[j]=array[j+1];array[j+1]=array[j];}}}
}

有下面两种创建线程的方法:

std::thread thread1(bubblesort,array1,LEN);
thread1.join();

1、创建线程thread1,运行函数bubblesort。对于thread构造函数,其第一个参数为所执行函数的名称(可能是引用),后面的参数则为所执行函数的参数。

std::thread (bubblesort,array1,LEN).join();

2、直接创建线程(无名称),并以规定的方式运行程序。

下面给出创建线程运行的例子,以及单线程运行的对比程序。两程序输出结果均为排序算法运行时间。读者可以自行验证,多线程的效率确实大有优势!

多线程:

#include <iostream>
#include <thread>
#include <ctime>
#include <cstdlib>#define LEN 100000void bubblesort(int* array,int len);int main(void)
{int* array1;int* array2;array1=new int[LEN];array2=new int[LEN];srand(time(0));for (int i=0;i<LEN;i++){array1[i]=(rand()%10000)*(rand()%10000);array2[i]=(rand()%10000)*(rand()%10000);}clock_t start_time=clock();std::thread thread1(bubblesort,array1,LEN);std::thread thread2(bubblesort,array2,LEN);thread1.join();thread2.join();clock_t stop_time=clock();std::cout<<1.0*(stop_time-start_time)/CLOCKS_PER_SEC; 
} void bubblesort(int* array,int len)
{for(int i=1;i<len;i++){for(int j=0;j<len-i;j++){if (array[j]>array[j+1]){int temp=array[j];array[j]=array[j+1];array[j+1]=array[j];}}}
}

单线程:

#include <iostream>
#include <thread>
#include <ctime>
#include <cstdlib>#define LEN 100000void bubblesort(int* array,int len);int main(void)
{int* array1;int* array2;array1=new int[LEN];array2=new int[LEN];srand(time(0));for (int i=0;i<LEN;i++){array1[i]=(rand()%10000)*(rand()%10000);array2[i]=(rand()%10000)*(rand()%10000);}clock_t start_time=clock();bubblesort(array1,LEN);bubblesort(array2,LEN);clock_t stop_time=clock();std::cout<<1.0*(stop_time-start_time)/CLOCKS_PER_SEC; 
} void bubblesort(int* array,int len)
{for(int i=1;i<len;i++){for(int j=0;j<len-i;j++){if (array[j]>array[j+1]){int temp=array[j];array[j]=array[j+1];array[j+1]=array[j];}}}
}

五、是否循环等待 detach和join

  • detach方式,启动的线程自主在后台运行,当前的代码继续往下执行,不等待新线程结束。
  • join方式,等待启动的线程完成,才会继续往下执行。

1、直接一个小实验分析join的用法

#include <thread>
#include <iostream>
#include <windows.h>//func1和func2这两个函数,分别打印对应内容10次 
void func1()
{	int count=0;while(count<=10){std::cout<<"thread1 working"<<std::endl;Sleep(1000);count++;}
}void func2()
{	int count=0;while(count<=10){std::cout<<"thread2 working"<<std::endl;Sleep(1000);count++;}
}int main(void)
{std::cout<<"one"<<std::endl;std::thread thread1(func1);std::thread thread2(func2);std::cout<<"two"<<std::endl;//这里使用了join,程序会一直循环等待 thread1.join();thread2.join();std::cout<<"three";
}

程序的输出结果是:

one
two
thread2 working
thread1 working
thread1 working
thread2 working
thread1 working
thread2 working
thread1 workingthread2 working

thread2 working
thread1 working
thread1 working
thread2 working
thread2 working
thread1 working
thread2 working
thread1 working
thread2 working
thread1 working
thread2 working
thread1 working
thread2 working
thread1 working
three

可以看出,位于join之前的one和two还是可以被打印的,而three要等到thread1和thread2执行完毕,才被打印。可以把join理解为循环等待函数。在thread1和thread2执行完毕前,主程序一直卡在里面不继续执行,知道两个线程结束,主程序才继续执行。

(此外,由于两线程一同占用输出流,可以看到thread1的某个换行符被吞掉了,我想这是两线程占用资源冲突造成的)

2、把join改为detach重复实验

int main(void)
{std::cout<<"one"<<std::endl;std::thread thread1(func1);std::thread thread2(func2);std::cout<<"two"<<std::endl;//这里使用了detach,主线程继续运行 thread1.detach();thread2.detach();std::cout<<"three";
}

one
two
thread1 working
thread2 working
three

可以看到thread1和thread2中的函数只执行了一次打印,主线程就结束了。那么子线程也结束了。

3、只改一个join呢?

int main(void)
{std::cout<<"one"<<std::endl;std::thread thread1(func1);std::thread thread2(func2);std::cout<<"two"<<std::endl;//这里使用了join,程序会一直循环等待 thread1.join();thread2.detach();std::cout<<"three";
}

one
two
thread1 working
thread2 working
thread1 workingthread2 working

thread1 workingthread2 working

thread1 workingthread2 working

thread2 working
thread1 working
thread2 working
thread1 working
thread1 working
thread2 working
thread2 working
thread1 working
thread1 workingthread2 working

thread1 working
thread2 working
thread1 working
thread2 working
three

这印证了我们对join的理解,它的的确确就是一个循环等待函数一般的存在(像arduino里和ROS里面一样)

上面这个例子,我们可以说吗,托thread1的福,thread2也得以运行完毕,但是如果thread2运行得慢一点,那么thread2依旧无法执行完毕。

4、继续做一些操作呢?

int main(void)
{std::cout<<"one"<<std::endl;std::thread thread1(func1);std::thread thread2(func2);std::cout<<"two"<<std::endl;thread1.detach();std::cout<<"three"<<std::endl;thread2.join();std::cout<<"four";
}

我把代码改成了这样,读者可以自行验证输出结果,非常有意思!

参考资料:
多线程的学习_多线程学习-CSDN博客

C++多线程详解(全网最全) - 知乎 (zhihu.com)

 

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

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

相关文章

linux设置定时任务

在Linux系统中设置定时任务通常使用的是Cron服务。以下是创建和管理定时任务的基本步骤&#xff1a; 打开crontab文件编辑器&#xff1a; 使用命令行工具编辑用户级别的cron任务列表&#xff1a; crontab -e 这将使用默认文本编辑器打开当前用户的crontab文件。 添加定时任务&…

[分布监控平台] Zabbis 监控

zabbix 是什么&#xff1f; zabbix 是一个基于 Web 界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。zabbix 能监视各种网络参数&#xff0c;保证服务器系统的安全运营&#xff1b;并提供灵活的通知机制以让系统管理员快速定位/解决存在的各种问题。 zabbix …

为什么需要消息中间件?

1.消息中间件是什么 消息队列&#xff08;MQ&#xff09;是一种系统间相互写作的通信机制&#xff0c;目前业界通常由两种方式来实现系统间通信&#xff0c;其中一种是基于远程过程调用的方式;另一种是基于消息队列的方式。前一种就是我们常说的RPC调用&#xff0c; 客户端不需…

leetcode—字母异位词

1 字母异位词分组 给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 1: 输入: strs ["eat", "tea", "tan", "ate",…

Linux 系统中常见的命令,它们用于执行各种任务,包括文件和目录管理、系统信息查看、用户管理等

以下是一些在 Linux 系统中常见的命令&#xff0c;它们用于执行各种任务&#xff0c;包括文件和目录管理、系统信息查看、用户管理等。这里列举了一些基础的命令&#xff1a; 文件和目录管理&#xff1a; ls: 列出目录内容。 ls cd: 切换当前目录。 cd /path/to/directory …

妹子回你消息冷淡了怎么办

她回信息慢&#xff0c;对你冷淡&#xff0c;怎么办? 你在微信上主动找她聊天&#xff0c;她回答你回得慢&#xff0c;慢慢的&#xff0c;你会觉得好像和她没戏了。然而&#xff0c;某一天她又突然主动找你聊天&#xff0c;对你又热情了一点&#xff0c;你觉得突然好像又有戏…

如何实现路由鉴权功能

什么是路由鉴权呢&#xff0c;分两个层面 1.如果我们还未登录的话&#xff0c;如果我们跳转其他路由&#xff0c;我们需要自动跳转到登陆页面&#xff0c;并且把跳转的目标路由通过query参数保留下来&#xff0c;点击登录之后&#xff0c;直接跳转过去即可 2.如果我们已经登录…

微信小程序之组件和API

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

SpringBoot教程(十二) | SpringBoot集成JPA

SpringBoot教程(十二) | SpringBoot集成JPA 1. JPA简介 概念&#xff1a; JPA顾名思义就是Java Persistence API的意思&#xff0c;是JDK 5.0注解或XML描述对象&#xff0d;关系表的映射关系&#xff0c;并将运行期的实体对象持久化到数据库中。 优势&#xff1a; 标准化 …

京东云无线宝一代64G加速版刷机记录

文章目录 确认型号刷机环境刷机步骤遇到的坑 确认型号 请确认你的型号是&#xff1a;RE-SP-01B。 拆机后flash芯片型号是&#xff1a;winband 25Q256JVFQ 刷机环境 win11不可以&#xff0c;CH341A的驱动识别不到&#xff0c;win10可以。 刷机步骤 避免重复造轮子。 参考知…

Linux驱动学习—IIC总线之FT5X06触摸驱动实验

1、实现触摸坐标值上报 流程图&#xff1a; 设备树如下&#xff1a; 触摸设备对应的设备树节点是&#xff1a; 读取坐标的寄存器&#xff1a; #include <linux/init.h> #include <linux/module.h> #include <linux/i2c.h> #include <linux/gpio.h> #i…

spring boot学习第七篇:通过spring boot使用redis

1、pom.xml文件里面增加如下依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </dependency> 2、yml文件增加如下配置&#xff1a; redis:host: loc…

【不用找素材】ECS 游戏Demo制作教程(3) 1.17

一、生成墓碑 新建脚本如下&#xff1a; using Unity.Entities; using Unity.Mathematics;namespace ECSdemo {public struct GraveyardRandom : IComponentData{public Random Value;}}扩充GraveyardMono如下&#xff1a; using Unity.Entities; using Unity.Mathematics; …

【计算机硬件】3、输入输出技术、总线结构

文章目录 输入输出技术内存与接口地址的编址方法1、 内存与接口地址独立编址方法2、内存与接口地址统一编址方法 计算机和外设间的数据交互方式1、程序控制(查询)方式2、程序中断方式3、DMA方式&#xff08;直接主存存取&#xff09; 总线结构 输入输出技术 内存与接口地址的编…

【思科】IPsec VPN 实验配置(动态地址接入)

【思科】IPsec VPN 实验配置&#xff08;动态地址接入&#xff09; 注意实验需求配置思路配置命令拓扑R1基础配置配置第一阶段 IKE SA配置第二阶段 IPsec SA ISP_R2基础配置 R3基础配置配置第一阶段 IKE SA配置第二阶段 IPsec SA PCPC1PC2 检查建立成功查看命令清除IKE / IPse…

C/C++ 基本数据类型的范围

一、常见的数据类型及其范围 数据类型Size(64位)范围int4Byteunsigned int4Bytelong4Byteunsigned long4Bytelong long8Byteunsigned long long8Byte 查询Size代码&#xff1a;sizeof(类型) 查询范围代码&#xff1a;numeric_limits<类型>::max和numeric_limits<类…

django大数据_草稿本01

文档 Learning_Spark/5.Spark Streaming/ReadMe.md at master LeslieZhoa/Learning_Spark # 在pyspark下运行 from pyspark.ml.feature import HashingTF,IDF,Tokenizer # 导入相关包# 创建一个dataframe&#xff0c;toDF为定义列名 sentenceData spark.createDataFrame([(0…

数据科学与大数据导论期末复习笔记(大数据)

来自于深圳技术大学&#xff0c;此笔记涵盖了期末老师画的重点知识&#xff0c;分享给大家。 等深分箱和等宽分箱的区别&#xff1a;等宽分箱基于数据的范围来划分箱子&#xff0c;每个箱子的宽度相等。等深分箱基于数据的观测值数量来划分箱子&#xff0c;每个箱子包含相同数量…

智慧校园大数据平台架构

平台架构 基础硬件层 基础硬件层是由一组低廉的PC或服务器组合构建而成。基础硬件层主要承载着数据的存储、运算、容错、调度和通信等任务,对基础应用层下达的指令进行执行和反馈。 数据集成 大数据特征表现在实时、交互、海量等方面,并且以半结构化、非结构化数据为主,价…

支付功能的实现

1.商户调用第三方支付服务的主要步骤流程&#xff1f; 1.1 表单跳转 前端点击提交支付&#xff0c;请求后端支付接口 支付接口通过阿里api生成表单信息返回给前端页面 同步回调&#xff0c;异步回调参数 请求参数&#xff1a;总金额&#xff0c;外部订单号 公共参数&#xff1…