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…...
计算机网络——数据链路层-可靠传输的实现机制:回退N帧协议GBN(无差错情况、累积确认、有差错情况、发送窗口尺寸)
目录 回退N帧协议GBN 介绍 无差错情况 累积确认 有差错情况 发送窗口尺寸 小结 练习 解析 示意图 上篇中所介绍的停止-等待协议的信道利用率很低;若出现超时重传,则信道利用率更低。 如果发送方在收到接收方的确认分组之前可以连续发送多个数…...
IDEA debug窗口左边工具栏隐藏与显示
今天在debug排查代码的时候一不小心点到哪里,结果变成这样 我们可以这样恢复,右键Debug 点击show Toolbar...
WPF 基于TableControl的页面切换
文章目录 前言其它项目的UserControl切换TableControl添加按钮,隐去TableItem的Header 结论 前言 我想用WPF简单实现一个按钮视图切换的效果,但是我发现别人的实现效果非常的麻烦。 其它项目的UserControl切换 我网上找了个开源的项目,他是…...
Lua 元表,元方法
元表与元方法的概念 Lua中每个值都可具有元表。元表是普通的Lua表,定义了原始值在某些特定操作下 的行为。 例如,当table作为加法的操作数时,Lua检查其“元表”中的“__add”字段是否有 个函数。如果有,Lua调用它执行加法。我们称“元表”中的“键(如__add)”为事件(event),称…...
C# WPF上位机开发(利用tcp/ip网络访问plc)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 c# wpf如果是用来开发非标上位机的,那么和plc的通信肯定是少不了的。而且,大部分plc都支持modbus协议,所以这个…...
Knife4j 接口文档如何设置 Authorization 鉴权参数?
🚀 作者主页: 有来技术 🔥 开源项目: youlai-mall 🍃 vue3-element-admin 🍃 youlai-boot 🌺 仓库主页: Gitee 💫 Github 💫 GitCode 💖 欢迎点赞…...
CentOS 防火墙管理及使用的redis基本常用命令
文章目录 防火墙管理使用systemctl管理防火墙启动、关闭使用firewalld-cmd配置访问防火墙策略firewalld配置文件修改限制来源IP docker使用 redis 防火墙管理 需要关闭防火墙或者开启对应端口 使用systemctl管理防火墙启动、关闭 启动防火墙: systemctl start fi…...
路由器原理
目录 一.路由器 1.路由器的转发原理 2.路由器的工作原理 二.路由表 1.路由表的形成 2.路由表表头含义 直连: 非直连: 静态 静态路由的配置 负载均衡(浮动路由) 默认路由 动态 三.交换与路由对比 一.路由器 1.路由器…...
采埃孚4D成像雷达拆解
1 基本信息 品牌:海外Tier1采埃孚 • 应用:上汽飞凡中高端纯电平台 • 数量:单车2个,安装在前后保内部 • 最远探测距离:350米 拆解来看,4D雷达主要可以分为4个部分,分别为数字接口板及结构件…...
若依框架springboot——修改前端图片上传样式
简述 使用过若依框架的,一定知道若依前端框架上传图片的样式,是一个正方形加号图片,但是如果你要使用自定义样式呢。 比如将下面这个图进行修改呢 修改后的样式 你可以直接找到element-ui 修改上传图片的组件,也可以加入新的组…...
wordpress创建配置文件/活动推广方式都有哪些
258. Add Digits Digit root 数根问题 /*** param {number} num* return {number}*/ var addDigits function(num) {var b (num-1) % 9 1 ;return b; };//之所以num要-1再1;是因为特殊情况下:当num是9的倍数时,09的数字根和0的数字根不同。 性质说明 …...
做网站怎么排版/手机免费建站系统
第一篇:第二章(为圆满人生做准备) 开篇 开篇就是讲习惯很重要,习惯就像引力,坏的习惯可以阻碍我们(天天不学无术吃喝嫖赌),好的习惯可以帮助我们(天天读书天天锻炼&…...
wordpress css3/有什么平台可以推广
//PS2键盘测试程序,可换行,按shift不放接着输入//可输出大写,按下CAPS输出大写,再次按下输出小写//此程序只用来测试,代码冗余,仅供参考,可根据需要自行删减//PA13->PS2.CLK PA15->PS2.D…...
用dw做网站怎么单独修改字体/全国疫情地区查询最新
一、写在前面之前写过一篇用Python发送天气预报邮件的博客,但是因为要手动输入城市名称,还要打开邮箱才能知道天气情况,这也太麻烦了。于是乎,有了这一篇博客,这次我要做的就是用Python获取本机IP地址,并根…...
在对方网站做友情链接/大数据精准获客软件
protobuf介绍 由于网上关于protobuf的交互的资料比较零散,所以自己整理了一下关于protobuf前后端交互的资料,以作参考。 Google Protocol Buffers 简称 Protobuf,它提供了一种灵活、高效、自动序列化结构数据的机制,可以联想 XML&…...
网站 模板 安装/广西壮族自治区免费百度推广
Windows Phone笔记(10)使用独立存储(中) 在我们前面的笔记中了解如何通过使用IsolatedStorageSettings类来保存应用程序设置,也知道独立存储还可以通过使用使用 IsolatedStorageFile类存储文件和文件夹。在这篇笔记中,让我们一起来了解并学会使用Isolate…...