当前位置: 首页 > news >正文

c++ 中多线程的相关概念与多线程类的使用

1、多线程相关概念

1.1 并发、并行、串行

并发(Concurrent):并发是指两个或多个事件在同一时间间隔内运行。在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行。
同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行。

并行(Parallel):并行是指两个或者多个事件在同一时刻运行。当系统有一个以上CPU时,当一个CPU执行一个进程时,另一个CPU可以执行另一个进程,两个进程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。其实决定并行的因素不是CPU的数量,而是CPU的核心数量,比如一个CPU多个核也可以并行。如下图所示。当线程数超过cpu核心数时,部分线程变成了并发执行。
在这里插入图片描述
串行:并行和串行指的是任务的执行方式。并行指的是多个任务可以同时执行 。串行是指多个任务时,各个任务按顺序执行,完成一个之后才能进行下一个,它们在时间上是不可能发生重叠的。如下图所示:
在这里插入图片描述

1.2 同步、异步

阻塞(blocking)、非阻塞(non-blocking):可以简单理解为需要做一件事能不能立即得到返回应答,如果不能立即获得返回,需要等待,那就阻塞了(进程或线程就阻塞在那了,不能做其它事情),否则就可以理解为非阻塞(在等待的过程中可以做其它事情)。

同步(synchronous): 是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去;
同步是阻塞模式,其相当于单线程中的串行模式
同步就相当于是 当客户端发送请求给服务端,在等待服务端响应的请求时,客户端不做其他的事情。当服务端做完了才返回到客户端。这样的话客户端需要一直等待。

异步(asynchronous):是指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。
异步是非阻塞模式,多线程都是异步的
异步就相当于当客户端发送给服务端请求时,在等待服务端响应的时候,客户端可以做其他的事情,这样节约了时间,提高了效率

1.3 进程、线程

进程(Process):是正在运行的程序实体,并且包括这个运行的程序中占据的所有系统资源,比如说CPU(寄存器),IO,内存,网络资源等。同样一个程序,同一时刻被两次运行了,那么他们就是两个独立的进程。

线程(Thread):是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

进程与线程的区别

  • 线程程序执行的最小单位,而进程操作系统分配资源的最小单位;进程是系统资源分配的单位,线程是系统调度的单位。
  • 一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线;
  • 进程之间相互独立,进程之间不能共享资源,而一个进程内的线程可以共享所在进程的地址空间和其它资源。同时线程还有自己的栈和栈指针,程序计数器等寄存器。
  • 调度和切换速度:线程上下文切换(其包含共享资源)比进程上下文切换(其不包含共享资源)要快得多。

1.4 多线程

多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务。每个线程都有自己的专有寄存器(如栈指针、程序计数器),但代码区是共享的,即不同的线程可以执行同样的方法。多线程技术允许单个程序创建多个并行执行的线程来完成各自的任务,从而提高整体的处理性能。

多线程是一种机制,允许在程序中并发执行多个指令流,每个指令流都称为一个线程,彼此间互相独立。线程与进程相似,但线程更为轻量级,并且专注于执行单一的任务。多线程是多任务的特殊形式,它能够提高系统的效率,特别是在需要同时完成多项任务的情况下。

以上内容参考自 :https://blog.csdn.net/wang121213145/article/details/123828346

2、多线程编程关键知识

2.1 如何创建线程

1. 创建线程的一般方法
说明

  • 主线程从main开始执行,一旦主线程从main()返回,则整个程序(进程)结束
  • 如果主线程结束了,其他子线程还没执行完,一般会被操作系统强行终止(除非子线程设置为detach)
  • 通常我们创建的子线程从一个函数开始运行,一旦此函数运行完毕,代表这个线程运行结束
  • 如果想保持子线程一直运行,不要让主线程运行完毕(除非子线程设置为detach)

2.创建子线程的一般方法

  • 包含头文件:#include <thread>
  • 编写一个子线程开始执行的函数(初始函数)
  • 使用thread()创建子线程
  • 设置主线程和子线程的关系,join()或detach()
  • join() 表示子线程会阻塞主线程的运行,detach()单独运行
2.1.1 thread()

(1)先看一个示例,这里子线程myprint和主线程main并发运行

#include <iostream>
#include <thread>
#include<windows.h>
using namespace std;//子线程的初始函数
void printThread(int theadId)
{cout << "我的线程开始执行:" <<theadId<< endl;Sleep(1000);cout << "我的线程执行完毕" << endl;
}//主线程在从main开始执行,一旦主线程从main()返回,则整个程序结束 
int main()
{//创建子线程(这两行在main函数里)int theadId=100;thread thread1(printThread,theadId);	//创建了线程,执行起点是printThread,同时让子线程开始执行thread1.join();			//主线程阻塞在这里,等子线程执行完。如果不加join,主线程结束了,子线程还在运行会导致程序崩溃cout << "Hello World!\n";	return 0;
}

-----运行结果--------


我的线程开始执行:100
我的线程执行完毕
Hello World!\n

(2)关于thread

  • thread是一个类

  • thread thread1(printThread,theadId);是利用构造函数创建了thread对象,传入参数是一个函数名称及对应函数的参数
    这行代码创建了一个线程对象,执行起点是printThread函数入口;并启动了子线程。

  • C++11 functional对函数指针做了拓展,可调用对象包括函数指针和函数对象等

2.1.2 join()
  • join 是 thread 类中的一个方法

  • 作用:阻塞主线程(其不会阻塞子线程),让主线程等待子线程执行完毕,然后子线程和主线程汇合,再往下执行

  • 如果把上面的thread1.join();注释掉,可能会看到输出混乱(在部分电脑上会直接引发报错,因为主线程线运行结束了),而且弹出异常提示
    (1) 由于主线程和子线程交替执行,所以打印混乱
    (2) 由于子线程没有结束主线程就结束了,子线程被操作系统强制结束,所以报异常

  • 一旦把线程join了,就不能再detach了(否则报异常),我们自己来控制子进程

  • 如果主线程执行完毕了,但是子线程没有执行完毕,这种程序是不稳定的,所以我们应该尽量保证主线程在所有子线程运行结束后再结束。

2.1.3 detach()

传统多线程程序,主线程要等待所有子线程执行完再退出,但C++11增加了detach(),可以不这样干了

  • detach 是 thread 类中的一个方法

  • 作用:将子线程和主线程分离,分离后的子线程与主线程没有关联,主线程结束后如果子线程还没有结束,那么会在后台继续运行,当子线程执行完毕后,由运行时库负责清理该线程相关资源

  • 一旦把线程detach了,就不能再join回来了(否则报异常),我们失去了对这个进程的控制。

thread thread1(printThread);
thread1.detach();
2.1.4 joinable()
  • joinable 是 thread 类中的一个方法

  • 作用:用来判断线程是否可以成功使用join 和 detch
    返回值:

      True:可以进行join()或detach();False:不能进行join()或detach()
    
  • 在 进行join()或者detach()操作时先进行判断,然后再操作

thread thread1(printThread);
if (thread1.joinable())
{thread1.join();
}

这样可以避免系统报错

以上内容参考自:https://blog.csdn.net/wxc971231/article/details/105979443

2.2 线程间变量同步

C++线程间线程间变量同步使基于共享内存是实现的(即多个线程使用同一个变量名),在线程a访问变量时可能存在线程b正在修改变量的情况,故需要设置线程安全机制。

1.互斥锁(Mutex):互斥锁是一种同步机制,用于防止多个线程同时访问共享资源。主要方法包括两个,分别是 Lock 和 Unlock。当一个线程获得互斥锁时,其他线程将被阻塞,直到该线程释放锁。互斥锁的优点是可以避免死锁,缺点是可能会导致线程饥饿。

2.条件变量(Ondition variable):条件变量是一种同步机制,用于在多个线程之间传递信号。当一个线程等待某个条件时,它可以调用条件变量的wait()方法来阻塞自己。 while (workq == NULL), 其workq为条件变量,通过while 死循环阻塞程序向后运行 ,通过条件变量可以一次性阻塞或者激活多个线程

3.信号量(Semaphore):信号量是一种同步机制,用于控制对共享资源的访问。当一个线程需要访问共享资源时,它必须先获取信号量。如果信号量的值为0,则线程将被阻塞,直到另一个线程释放信号量。其本质是通过一个变量来控制多个线程的运行,当变量值为n时,表示允许运行n个线程,每运行一个线程值减1;当n为0时,表示没有资源可供线程运行;当值为-n时,表示n个线程在等待运行;当线程运行结束,n的值则加一,表示释放一个线程执行机会 ,信号量的优点是可以避免死锁和线程饥饿,缺点是可能会导致信号量竞争。从实现上来说一个信号量可以是用mutex + counter + condition variable

4.管道(Pipe):管道是一种进程间通信机制,但也可以用于线程间通信。管道是一个字节流,可以用于在两个线程之间传递数据。管道的优点是简单易用,缺点是只能用于有亲缘关系的线程之间通信。 具体可以参考:https://blog.csdn.net/skyroben/article/details/71513385

3、基于面相对象的多线程类使用

在多线程操作中常见的问题是:生产者-消费者问题,生产者用于生成数据,消费者用于处理数据,二者间通过共用一个变量进行信息交互。
在这里插入图片描述
前文所提到的线程创建方法为基于函数的,在实际使用过程中以面向对象进行开发,需要将函数相关的功能封装成class。在面向对象中多线程类也可以通过std::thread进行实现,具体可以参考以下代码。

其GetImage为生产者,DealImage为消费者,imglist为两者间的共享变量,mtx为互斥锁。


#include <iostream> 
#include <thread>
#include <windows.h>
#include <opencv2/opencv.hpp>
using namespace std; 
using namespace cv;using namespace std;
std::mutex mtx; // 保护对imglist的访问
vector<Mat> imglist;
//------------获取图像的线程类,imglist的元素在增多---------------
class GetImage
{
public:GetImage(vector<Mat>& imglist);void startWork();void work();static void threadFunc(GetImage*);
};GetImage::GetImage(vector<Mat>& imglist) {
}void GetImage::work()
{int count = 0;while (1){Mat mat;mtx.lock();imglist.push_back(mat);mtx.unlock();cout <<"容器内数据量:  " <<imglist.size() << endl;Sleep(300);}
}void GetImage::threadFunc(GetImage* arg)
{arg->work();
}void GetImage::startWork()
{std::thread work_thread(threadFunc, this);work_thread.detach();
}//------------处理图像的线程类,imglist的元素在减少---------------
class DealImage
{
public:DealImage(vector<Mat>& DealImage);void startWork();void work();static void threadFunc(DealImage*);
};DealImage::DealImage(vector<Mat>& imglist) {
}
void DealImage::work()
{int count = 0;while (1){if (imglist.size() > 0) {Mat mat = imglist[imglist.size()-1];//获取最后一个元素cout << "获取到一张图片 ,剩余图像:" << imglist.size() - 1 <<endl;mtx.lock();imglist.pop_back();//删除最后一个元素mtx.unlock();//---这里写图像处理函数---}else {cout << "--------没有获取到一张图片--------" << endl;}Sleep(400);}
}void DealImage::threadFunc(DealImage* arg)
{arg->work();
}void DealImage::startWork()
{std::thread work_thread(threadFunc, this);work_thread.detach();
}int main()
{GetImage* t1 = new GetImage(imglist);t1->startWork();DealImage* t2 = new DealImage(imglist);t2->startWork();while (1){Sleep(1);}return 0;
}

相关文章:

c++ 中多线程的相关概念与多线程类的使用

1、多线程相关概念 1.1 并发、并行、串行 并发&#xff08;Concurrent&#xff09;&#xff1a;并发是指两个或多个事件在同一时间间隔内运行。在操作系统中&#xff0c;是指一个时间段中有几个程序都处于已启动运行到运行完毕之间&#xff0c;且这几个程序都是在同一个处理机…...

深入理解 hash 和 history:网页导航的基础(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…...

腾讯文档助力CRM集成:无代码连接电商与广告

腾讯文档API的简介与优势 腾讯文档API是一个强大的工具&#xff0c;它允许企业通过简单的无代码开发来实现与电商平台和客服系统的智能连接。这种连接不仅提高了工作效率&#xff0c;还优化了数据管理。使用腾讯文档智能表&#xff0c;商家可以享受多样的列类型、多维视图展示…...

学习使用echarts漏斗图的参数配置和应用场景

学习使用echarts漏斗图的参数配置和应用场景 前言什么是漏斗图漏斗图的特点及应用场景漏斗图的特点漏斗图常见的的应用场景&#xff1a; echarts中漏斗的常用属性echart漏斗代码美化漏斗图样式1、设置标题字体大小2、设置标签样式3、设置漏斗图为渐变颜色4、设置高亮效果5、设置…...

npm ,yarn 更换使用国内镜像源,阿里源,清华大学源

在平时开发当中&#xff0c;我们经常会使用 Npm&#xff0c;yarn 来构建 web 项目。但是npm默认的源的服务器是在国外的&#xff0c;如果没有梯子的话。会感觉特别特别慢&#xff0c;所以&#xff0c;使用国内的源是非常有必要的。 在这里插入图片描述 Nnpm&#xff0c; yarn …...

vue+react题集整理

1.Typescript中 interface 和 type 的差别是什么&#xff1f; interface只能用来描述对象类型 type可以描述任何类型组合 type后边需要有 interface后边没有 当多次使用相同名称定义一个 interface 时&#xff0c;它们会自动合并为一个接口。同名属性的不能进行类型覆盖修改&am…...

线程池ThreadPoolExecutor详解

线程池ThreadPoolExecutor详解 大家好&#xff0c;我是微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天&#xff0c;让我们深入研究Java中线程池的强大工具——ThreadPoolExecutor&#xff0c;解析它的工作原理、配置参数…...

elasticsearch|大数据|kibana的安装(https+密码)

前言&#xff1a; kibana是比较好安装的&#xff0c;但https密码就比较麻烦一些了&#xff0c;下面将就如何安装一个可在生产使用的kibana做一个简单的讲述 一&#xff0c; kibana版本和下载地址 这里我想还是强调一下&#xff0c;kibana的版本需要和elasticsearch的版本一…...

vue javascript tree 层级数据处理

层级数据是有父子关系的数组&#xff0c;示例&#xff1a; const treeData [{id: 1b7e8e98cb1d4a1f81e4fe2dfd9a8458,name: 层级1,parentId: null,children: [{id: 0d45dd5bb4c14d64a3ab0b738add4b24,name: 层级1-1,parentId: 1b7e8e98cb1d4a1f81e4fe2dfd9a8458,children: [{…...

WPF仿网易云搭建笔记(4):信息流控制之消息订阅

文章目录 专栏和Gitee仓库前言消息订阅最简单的案例简单用例父组件订阅子组件回调 结果 消息订阅机制消息token是A还是B?传递消息的载体。双重token重复订阅问题 结论 专栏和Gitee仓库 WPF仿网易云 Gitee仓库 WPF仿网易云 CSDN博客专栏 前言 上一篇文章中&#xff0c;我们简单…...

持续集成交付CICD:GitLabCI操作Harbor仓库

目录 一、实验 1.GitLabCI操作Harbor仓库 二、问题 1.gitlab-runner连接docker daemon报错 一、实验 1.GitLabCI操作Harbor仓库 &#xff08;1&#xff09;修改GitLabCI共享库代码并提交到mater CI.yaml .pipelineInit:tags:- buildstage: .prevariables:GIT_CHECKOUT: …...

[C++]——学习模板

了解模板——初阶 前言&#xff1a;一、模板1.1 什么是模板1.2 模板的概念1.3 模板可以做什么1.4 泛型模板 二、函数模板2.1 函数模板概念和格式2.2 函数模板原理2.3 函数模板实例化2.3.1 隐式实例化2.3.2 显式实例化 2.4 模板参数的匹配原则2.5 函数模板声明定义分离 三、类模…...

大数据技术14:FlinkCDC数据变更捕获

前言&#xff1a;Flink CDC是Flink社区开发的flink-cdc-connectors 组件&#xff0c;这是⼀个可以直接从 MySQL、PostgreSQL 等数据库直接读取全量数据和增量变更数据的 source 组件。 https://github.com/ververica/flink-cdc-connectors 一、CDC 概述 CDC 的全称是 Change …...

SpringDataRedis 基本使用

1.1 简介 1.1.1 概述 Spring Data 中有一个成员 Spring Data Redis&#xff0c;他提供了 RedisTemplate 可以在 Spring 应用中更简便的访问 Redis 以及异常处理及序列化&#xff0c;支持发布订阅等操作。 1.2 RedisTemplate 常见 API   RedisTemplate 针对 jedis 客户端中大…...

蓝牙物联网智慧工厂解决方案

蓝牙物联网智慧工厂解决方案是一种针对工厂管理的智能化解决方案&#xff0c;通过蓝牙、物联网、大数据、人工智能等技术&#xff0c;实现工厂人员的定位、物资的定位管理、车间的智慧巡检、智慧安防以及数据的可视化等功能。 蓝牙物联网智慧工厂解决方案构成&#xff1a; 人员…...

html的学习笔记

开发工具&#xff1a;vscode 文字标签 h1:一级标题&#xff0c;h2&#xff1a;二级标题h6 p&#xff1a;段落标签 hr&#xff1a;分隔线 br&#xff1a;换行 strong/b&#xff1a;文字加粗 ins/u:下划线 em/i&#xff1a;倾斜 del/s&#xff1a;删除线 媒体标签 图片…...

每日一道算法题 8(2023-12-16)

题目描述 给定一个仅包含0和1的n*n二维矩阵 请计算二维矩阵的最大值 计算规则如下 每行元素按下标顺序组成一个二进制数(下标越大约排在低位)&#xff0c; 二进制数的值就是该行的值&#xff0c;矩阵各行之和为矩阵的值 允许通过向左或向右整体循环移动每个元素来改变元素在行…...

Unity项目优化案例二

本文地址&#xff1a;https://blog.csdn.net/t163361/article/details/135024136 针对工作中遇到的优化问题&#xff0c;记录一下&#xff0c;给大家优化自己的项目提供一些思路。 公司产品最近正给国内某大型赛事做支撑服务暴露出不少问题。 使用环境 Unity 2021.3.0f1 cpu…...

如何发布自定义 npm 组件包

准备工作 1. 注册 npm 账号 还没有 npm 账号&#xff1f;去官网注册&#xff1a; https://www.npmjs.com 需要记住用户名、密码、邮箱&#xff0c;后面需要用到。 2. 查看本地 npm 镜像&#xff0c;如果不是默认的&#xff0c;需要改回来 npm config get registry重置镜像路…...

iOS_给View的部分区域截图 snapshot for view

文章目录 1.将整个view截图返回image&#xff1a;2.截取view的部分区域&#xff0c;返回image&#xff1a;3.旧方法&#xff1a;4.Tips参考&#xff1a; 1.将整个view截图返回image&#xff1a; 这些 api 已被废弃&#xff0c;所以需要判断 iOS 版本 写两套代码&#xff1a; R…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

基于TurtleBot3在Gazebo地图实现机器人远程控制

1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

三分算法与DeepSeek辅助证明是单峰函数

前置 单峰函数有唯一的最大值&#xff0c;最大值左侧的数值严格单调递增&#xff0c;最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值&#xff0c;最小值左侧的数值严格单调递减&#xff0c;最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...

libfmt: 现代C++的格式化工具库介绍与酷炫功能

libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库&#xff0c;提供了高效、安全的文本格式化功能&#xff0c;是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全&#xff1a…...

使用SSE解决获取状态不一致问题

使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件&#xff0c;这个上传文件是整体功能的一部分&#xff0c;文件在上传的过程中…...

智警杯备赛--excel模块

数据透视与图表制作 创建步骤 创建 1.在Excel的插入或者数据标签页下找到数据透视表的按钮 2.将数据放进“请选择单元格区域“中&#xff0c;点击确定 这是最终结果&#xff0c;但是由于环境启不了&#xff0c;这里用的是自己的excel&#xff0c;真实的环境中的excel根据实训…...

【优选算法】模拟 问题算法

​一&#xff1a;替换所有的问号 class Solution { public:string modifyString(string s) {int n s.size();for(int i 0; i < n; i){if(s[i] ?){for(char ch a; ch < z; ch){if((i0 && ch !s[i1]) || (in-1 && ch ! s[i-1]) || ( i>0 &&…...

BERT, GPT, Transformer之间的关系

1. Transformer 是什么&#xff1f;简单介绍 1.1 通俗理解 想象你是一个翻译员&#xff0c;要把一句话从中文翻译成英文。你需要同时看句子里的每个词&#xff0c;理解它们之间的关系。Transformer就像一个超级翻译助手&#xff0c;它用“自注意力机制”&#xff08;Attentio…...

2480: 2020年06月2级T1:计算矩阵边缘元素之和

题目描述 2020年06月2级第一题题目&#xff1a;计算矩阵边缘元素之和 输入一个整数矩阵&#xff0c;计算位于矩阵边缘的元素之和。所谓矩阵边缘的元素&#xff0c;就是第一行和最后一行的元素以及第一列和最后一列的元素。 输入 第一行分别为矩阵的行数m和列数n&#xff0…...