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 并发、并行、串行 并发(Concurrent):并发是指两个或多个事件在同一时间间隔内运行。在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机…...

深入理解 hash 和 history:网页导航的基础(下)
🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云…...

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

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

npm ,yarn 更换使用国内镜像源,阿里源,清华大学源
在平时开发当中,我们经常会使用 Npm,yarn 来构建 web 项目。但是npm默认的源的服务器是在国外的,如果没有梯子的话。会感觉特别特别慢,所以,使用国内的源是非常有必要的。 在这里插入图片描述 Nnpm, yarn …...
vue+react题集整理
1.Typescript中 interface 和 type 的差别是什么? interface只能用来描述对象类型 type可以描述任何类型组合 type后边需要有 interface后边没有 当多次使用相同名称定义一个 interface 时,它们会自动合并为一个接口。同名属性的不能进行类型覆盖修改&am…...
线程池ThreadPoolExecutor详解
线程池ThreadPoolExecutor详解 大家好,我是微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天,让我们深入研究Java中线程池的强大工具——ThreadPoolExecutor,解析它的工作原理、配置参数…...

elasticsearch|大数据|kibana的安装(https+密码)
前言: kibana是比较好安装的,但https密码就比较麻烦一些了,下面将就如何安装一个可在生产使用的kibana做一个简单的讲述 一, kibana版本和下载地址 这里我想还是强调一下,kibana的版本需要和elasticsearch的版本一…...

vue javascript tree 层级数据处理
层级数据是有父子关系的数组,示例: 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博客专栏 前言 上一篇文章中,我们简单…...

持续集成交付CICD:GitLabCI操作Harbor仓库
目录 一、实验 1.GitLabCI操作Harbor仓库 二、问题 1.gitlab-runner连接docker daemon报错 一、实验 1.GitLabCI操作Harbor仓库 (1)修改GitLabCI共享库代码并提交到mater CI.yaml .pipelineInit:tags:- buildstage: .prevariables:GIT_CHECKOUT: …...

[C++]——学习模板
了解模板——初阶 前言:一、模板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数据变更捕获
前言:Flink CDC是Flink社区开发的flink-cdc-connectors 组件,这是⼀个可以直接从 MySQL、PostgreSQL 等数据库直接读取全量数据和增量变更数据的 source 组件。 https://github.com/ververica/flink-cdc-connectors 一、CDC 概述 CDC 的全称是 Change …...
SpringDataRedis 基本使用
1.1 简介 1.1.1 概述 Spring Data 中有一个成员 Spring Data Redis,他提供了 RedisTemplate 可以在 Spring 应用中更简便的访问 Redis 以及异常处理及序列化,支持发布订阅等操作。 1.2 RedisTemplate 常见 API RedisTemplate 针对 jedis 客户端中大…...

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

html的学习笔记
开发工具:vscode 文字标签 h1:一级标题,h2:二级标题h6 p:段落标签 hr:分隔线 br:换行 strong/b:文字加粗 ins/u:下划线 em/i:倾斜 del/s:删除线 媒体标签 图片…...
每日一道算法题 8(2023-12-16)
题目描述 给定一个仅包含0和1的n*n二维矩阵 请计算二维矩阵的最大值 计算规则如下 每行元素按下标顺序组成一个二进制数(下标越大约排在低位), 二进制数的值就是该行的值,矩阵各行之和为矩阵的值 允许通过向左或向右整体循环移动每个元素来改变元素在行…...
Unity项目优化案例二
本文地址:https://blog.csdn.net/t163361/article/details/135024136 针对工作中遇到的优化问题,记录一下,给大家优化自己的项目提供一些思路。 公司产品最近正给国内某大型赛事做支撑服务暴露出不少问题。 使用环境 Unity 2021.3.0f1 cpu…...

如何发布自定义 npm 组件包
准备工作 1. 注册 npm 账号 还没有 npm 账号?去官网注册: https://www.npmjs.com 需要记住用户名、密码、邮箱,后面需要用到。 2. 查看本地 npm 镜像,如果不是默认的,需要改回来 npm config get registry重置镜像路…...

iOS_给View的部分区域截图 snapshot for view
文章目录 1.将整个view截图返回image:2.截取view的部分区域,返回image:3.旧方法:4.Tips参考: 1.将整个view截图返回image: 这些 api 已被废弃,所以需要判断 iOS 版本 写两套代码: R…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...

手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...

面向无人机海岸带生态系统监测的语义分割基准数据集
描述:海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而,目前该领域仍面临一个挑战,即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

9-Oracle 23 ai Vector Search 特性 知识准备
很多小伙伴是不是参加了 免费认证课程(限时至2025/5/15) Oracle AI Vector Search 1Z0-184-25考试,都顺利拿到certified了没。 各行各业的AI 大模型的到来,传统的数据库中的SQL还能不能打,结构化和非结构的话数据如何和…...

Sklearn 机器学习 缺失值处理 获取填充失值的统计值
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 使用 Scikit-learn 处理缺失值并提取填充统计信息的完整指南 在机器学习项目中,数据清…...

Matlab实现任意伪彩色图像可视化显示
Matlab实现任意伪彩色图像可视化显示 1、灰度原始图像2、RGB彩色原始图像 在科研研究中,如何展示好看的实验结果图像非常重要!!! 1、灰度原始图像 灰度图像每个像素点只有一个数值,代表该点的亮度(或…...