【c++高级篇】--多任务编程/多线程(Thread)
目录
1.进程和线程的概念:
1.1 进程(Process):
1.2线程(Thread):
1.3 对比总结:
2.多线程编程:
2.1 基于线程的多任务处理(Thread):
2.1.1. mbed.h 中的线程类
2.2 注意事项:(死锁)
2.2.1. 进程死锁
2.2.2 线程死锁
2.2.3 避免死锁(Thread):
1.进程和线程的概念:
进程和线程是操作系统中两个重要的概念,它们之间存在着密切的关系,但有不同的特性和用途。
1.1 进程(Process):
- 操作系统中资源分配的最小单位,每个进程拥有独立的内存空间、系统资源(文件描述符、网络连接等)和生命周期。进程之间相对独立,无法直接共享彼此的内存空间。
 
进程虽然无法直接共享彼此内存空间 ,但是操作系统提供了一些机制,使得进程之间可以共享或交换部分资源,但这些共享和通信需要通过特殊的手段实现,而不是像线程那样直接访问共享的内存空间。
进程间资源共享的常用方式:
-  
管道(Pipe):允许一个进程将数据写入管道,另一个进程从管道中读取,用于单向通信。
 -  
消息队列(Message Queue):操作系统提供的一种数据结构,用于在多个进程之间发送和接收消息,实现异步通信。
 -  
共享内存(Shared Memory):一种特殊的内存区域,多个进程可以映射到这个区域来进行数据共享。共享内存速度快,但需要借助信号量等同步机制,避免数据竞争。
 -  
信号量(Semaphore):用来控制对共享资源的访问,防止多个进程同时访问导致冲突。
 -  
套接字(Socket):尤其用于分布式系统中,通过网络通信实现跨进程的数据共享和传递。
 
1.2线程(Thread):
- 是操作系统中CPU调度的最小单位。线程共享同一进程的内存空间和系统资源,可以认为是进程中的“轻量级”执行单元。同一进程中的线程之间能够共享全局变量和数据,通讯成本低。
 
1.3 对比总结:

 2.多线程编程:
 
多线程是多任务处理的一种特殊形式,多任务处理允许让电脑同时运行两个或两个以上的程序。在一般情况下,有两种类型的多任务处理:基于进程和基于线程。
-  
基于进程的多任务处理:每个进程都有自己的内存空间和系统资源,进程之间相对独立,切换开销较大,但安全性高。每个进程可以运行不同的程序,相互之间的通信通常需要更复杂的机制,比如进程间通信(IPC)。
 -  
基于线程的多任务处理:线程是进程内的一个执行单元,多个线程共享同一进程的内存空间和资源,因此切换开销相对较小,适合需要频繁进行上下文切换的任务。由于共享内存,线程间的通信更为高效,但也带来了同步和安全性的问题。
 
2.1 基于线程的多任务处理(Thread):
以嵌入式单片为例,在mbed OS中,mbed.h库提供了对线程的支持,使得在嵌入式系统中可以方便地实现多线程。
2.1.1. mbed.h 中的线程类
 
在mbed.h库中,线程主要通过 Thread 类来管理和操作。该类提供了创建、启动、暂停、恢复和终止线程的基本操作方法。
常用的 Thread 类方法有:
Thread::start(callback):启动线程,执行指定的回调函数。Thread::join():阻塞当前线程,直到其被调用线程完成。(顺序执行),调用join()后,主线程会被阻塞,直到子线程执行完毕。Thread::terminate():强制终止线程的执行。Thread::yield():让出CPU,使其他线程有机会运行。Thread::sleep_for(milliseconds):使线程在指定的毫秒数内休眠。
#include "mbed.h"// 定义LED灯
DigitalOut led1(LED1);
DigitalOut led2(LED2);// 定义线程
Thread thread1;
Thread thread2;// 线程函数1 - 控制LED1闪烁
void led1_thread() {while (true) {led1 = !led1;  // 切换LED1的状态ThisThread::sleep_for(500ms);  // 每500ms切换一次}
}// 线程函数2 - 控制LED2闪烁
void led2_thread() {while (true) {led2 = !led2;  // 切换LED2的状态ThisThread::sleep_for(1000ms);  // 每1000ms切换一次}
}int main() {// 启动线程thread1.start(led1_thread);thread2.start(led2_thread);// 主线程可以执行其他任务,或等待子线程结束thread1.join();thread2.join();
}
 
 
2.2 注意事项:(死锁)
进程死锁和线程死锁都涉及资源的相互等待,导致无法继续执行。
2.2.1. 进程死锁
进程死锁发生在两个或多个进程之间。当进程A持有资源1并等待资源2,而进程B持有资源2并等待资源1时,两个进程将永远处于等待状态,无法继续执行。
特征
-  
互斥:资源只能被一个进程占用。(不同同时访问)
 -  
持有并等待:进程在持有至少一个资源的情况下,申请其他资源。
 -  
不剥夺:已经分配给进程的资源在其完成之前不能被强制剥夺。
 -  
循环等待:存在一种进程资源的循环等待关系。
 
示例
进程A持有资源R1,并请求资源R2。 进程B持有资源R2,并请求资源R1。 
2.2.2 线程死锁
定义
在多线程程序中,线程死锁通常发生在多个线程尝试以不同的顺序获取多个锁时。例如,线程1持有锁A并等待锁B,而线程2持有锁B并等待锁A,这将导致两个线程永远处于等待状态。
特征
-  
与进程死锁相似,同样具有互斥、持有并等待、不剥夺和循环等待的特征。
 -  
线程死锁通常更复杂,因为线程之间的锁依赖关系可能更难以追踪
 
2.2.3 避免死锁(Thread):
同步和锁
同步指的是在多个线程之间协调它们的执行顺序,以确保某些操作以特定的顺序完成,防止出现竞态条件(race condition)。同步的目的在于确保共享资源的安全访问。
方法:同步可以通过多种方式实现,包括:
- 互斥锁(Mutex):保证在某一时刻只有一个线程可以访问某个资源。
 - 信号量(Semaphore):控制同时访问某个资源的线程数量。
 - 条件变量(Condition Variable):使线程在某些条件不满足时阻塞,直到条件满足。
 - 读写锁(Read-Write Lock):允许多个线程同时读数据,但在写数据时需要独占访问。
 
互斥锁(Mutex):
#include "mbed.h"Mutex mutex;  // 创建一个互斥锁
int sharedResource = 0;  // 共享资源void threadTask() {for (int i = 0; i < 5; i++) {mutex.lock();  // 加锁,开始访问共享资源sharedResource++;  // 修改共享资源printf("线程 %d 修改共享资源: %d\n", ThisThread::get_id(), sharedResource);mutex.unlock();  // 解锁,释放共享资源ThisThread::sleep_for(500ms);}
}int main() {Thread thread1;Thread thread2;thread1.start(threadTask);thread2.start(threadTask);thread1.join();thread2.join();printf("最终共享资源值: %d\n", sharedResource);return 0;
}
 
- 互斥锁(
mutex)确保在同一时刻只有一个线程可以访问和修改sharedResource,避免了数据竞争。 - 每个线程在修改共享资源前调用
mutex.lock(),完成后调用mutex.unlock(),以确保资源安全。 
读写锁(Read-Write Lock):
#include "mbed.h"RWLock rwLock;  // 创建读写锁
int sharedData = 0;  // 共享数据// 读线程
void readTask() {for (int i = 0; i < 5; i++) {rwLock.lock_read();  // 获取读锁printf("读线程 %d 读取共享数据: %d\n", ThisThread::get_id(), sharedData);rwLock.unlock_read();  // 释放读锁ThisThread::sleep_for(500ms);}
}// 写线程
void writeTask() {for (int i = 0; i < 3; i++) {rwLock.lock_write();  // 获取写锁sharedData++;  // 更新共享数据printf("写线程 %d 更新共享数据: %d\n", ThisThread::get_id(), sharedData);rwLock.unlock_write();  // 释放写锁ThisThread::sleep_for(1000ms);}
}int main() {Thread readThreads[5];Thread writeThread;// 启动多个读线程for (int i = 0; i < 5; i++) {readThreads[i].start(readTask);}// 启动一个写线程writeThread.start(writeTask);// 等待所有线程完成for (int i = 0; i < 5; i++) {readThreads[i].join();}writeThread.join();printf("所有任务完成\n");return 0;
}
 
-  
多个读线程(
readTask)同时读取共享数据sharedData。由于使用了读写锁,多个读线程可以并行地访问共享数据。 -  
写线程(
writeTask)在更新共享数据时,必须获取写锁,这会阻止其他线程(无论是读线程还是写线程)访问共享数据,直到写操作完成。 
相关文章:
【c++高级篇】--多任务编程/多线程(Thread)
目录 1.进程和线程的概念: 1.1 进程(Process): 1.2线程(Thread): 1.3 对比总结: 2.多线程编程: 2.1 基于线程的多任务处理(Thread)…...
【力扣专题栏】两数相加,如何实现存储在链表中的整数相加?
题解目录 1、题目描述解释2、算法原理解析3、代码编写(原始版本)4、代码编写(优化版本) 1、题目描述解释 2、算法原理解析 3、代码编写(原始版本) /*** Definition for singly-linked list.* struct ListN…...
SOLID - 接口隔离原则(Interface Segregation Principle)
SOLID - 接口隔离原则(Interface Segregation Principle) 定义 接口隔离原则(Interface Segregation Principle,ISP)是面向对象设计中的五个基本原则之一,通常缩写为SOLID中的I。这一原则由Robert C. Martin提出&…...
arrylist怎么让他变得不可修改
在Java中,要将一个 ArrayList变得不可修改,你可以使用以下几种方法: ###1. 使用 Collections.unmodifiableList Java 提供了 Collections.unmodifiableList 方法,可以生成一个不可修改的视图。这种方式返回的列表将不允许添加、…...
SpringMVC实战(3):拓展
四、RESTFul风格设计和实战 4.1 RESTFul风格概述 4.1.1 RESTFul风格简介 RESTful(Representational State Transfer)是一种软件架构风格,用于设计网络应用程序和服务之间的通信。它是一种基于标准 HTTP 方法的简单和轻量级的通信协议&…...
Vue应用中使用xlsx库实现Excel文件导出的完整指南
Vue应用中使用xlsx库实现Excel文件导出的完整指南 在现代Web开发中,经常需要将数据导出为Excel文件,以便于用户进行离线分析或记录。Vue.js作为一个轻量级且高效的前端框架,结合xlsx库可以轻松实现这一功能。本文将详细介绍如何在Vue应用中使…...
【数据分析】Power BI的使用教程
目录 1 Power BI架构1.1 Power BI Desktop1.2 Power BI服务1.3 Power BI移动版 2 Power Query2.1 Power Query编辑器2.2 Power Query的优点2.3 获取数据2.4 数据清洗的常用操作2.4.1 提升标题2.4.2 更改数据类型2.4.3 删除错误/空值2.4.4 删除重复项2.4.5 填充2.4.6 合并列2.4.…...
融合ASPICE与敏捷开发:探索汽车软件开发的最佳实践
ASPICE(Automotive SPICE,即汽车软件过程改进和能力dEtermination)与敏捷开发在软件开发领域各自具有独特的价值和特点,它们之间的关系可以归纳为既相互区别又相互补充。 一、ASPICE的特点 ASPICE是汽车行业对软件开发流程的一个评…...
后台管理系统的通用权限解决方案(三)SpringBoot整合Knife4j生成接口文档
1 Knife4j介绍 knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案,前身是swagger-bootstrap-ui,取名knife4j是希望它能像一把匕首一样小巧,轻量,并且功能强悍! 其底层是对Springfox的封装,使…...
保研考研机试攻略:python笔记(1)
🐨🐨🐨宝子们好呀 ~ 我来更新欠大家的python笔记了,从这一篇开始我们来学下python,当然,如果只是想应对机试并且应试语言以C和C为主,那么大家对python了解一点就好,重点可以看高分篇…...
在浏览器中运行 Puppeteer:解锁新能力
Puppeteer,这个强大的浏览器自动化工具,通常在Node.js环境中运行。但你有没有想过,在浏览器本身中运行Puppeteer会是什么样子?这不仅能让我们利用Puppeteer的功能完成更多任务,还能避开Node.js特定的限制。 支持的功…...
Kafka消费者故障,出现活锁问题如何解决?
大家好,我是锋哥。今天分享关于【Kafka消费者故障,出现活锁问题如何解决?】面试题?希望对大家有帮助; Kafka消费者故障,出现活锁问题如何解决? 1000道 互联网大厂Java工程师 精选面试题-Java资…...
pytorch 交叉熵损失函数 BCELoss
BCE Loss 交叉熵损失函数计算公式: BCE Loss - 1/n*(y_actual * log(y_pred) (1 - y_actual) * log(1 - y_pred)) t[i]为标签值:0或者1 o[i]是经过sigmoid后的概率值 BCEWithLogitsLoss 这个损失将Sigmoid层和BCELoss合并在一个类中。 BCEWithLog…...
【进阶】面向对象之接口(多学三招)
文章目录 IDK8开始接口中新增的方法1.允许在接口中定义默认方法,需要使用关键字default修饰2.接口中的默认方法的定义格式3.接口中默认方法的注意事项总结 IDK8开始接口中新增的方法 JDK7以前:接口中只能定义抽象方法。JDK8的新特性:接口中可以定义有方法体的方法。(默认、静态…...
linux上trace code的几种方法
我们在看代码时,总是会遇到下面问题: 1.查看某个场景下的代码执行流 2.查看某个函数被执行时的routine 但是,如果直接查看源码,源码可能代码量大,且分支多,不容易理清。就需要让相关程序运行起来查看。 …...
文件操作(1) —— 文件基础知识
目录 1. 为什么使用文件? 2. 文件种类【按功能分】 3. 文件名 4. 数据文件种类【按存储方式细分】 5. 文件的打开和关闭 5.1 流和标准流 5.2 文件指针 5.3 文件的打开和关闭函数 6. 文件缓冲区 1. 为什么使用文件? 如果没有⽂件,我…...
4K双模显示器7款评测报告
4K双模显示器7款评测报告 HKC G27H7Pro 4K双模显示器 ROG华硕 XG27UCG 4K双模显示器 雷神 ZU27F160L 4K双模显示器 泰坦军团 P275MV PLUS 4K双模显示器 外星人(Alienware)AW2725QF 4K双模显示器 SANC盛色 D73uPro 4K双模显示器 ANTGAMER蚂蚁电竞 …...
2024.10.24华为(留学生)笔试题解
第一题集装箱堆叠 看注释即可 // 看题目,是最长连续序列的变种。底应该选大的,然后往上堆叠选择次大的(越接近底越好?) // 后续想一下,像是动态规划? // 再一想,好像排序后很容易处理#include <bits/stdc++.h> #include <functional> using namespace st…...
基于neo4j的医疗问诊系统
当你身体不适时,想要找到准确的答案却经常遇到模棱两可的答复,糟心吗?现在,基于neo4j的智能医疗问诊系统为你带来全新体验!我们设计了一个具备自动化问答功能的医疗系统,帮助用户快速获取专业的健康知识答案…...
java :String 类
在我们之前的讲解中我们已经了解了很多的Java知识,这节我们讲Java中字符如何定义以及关于String如何使用还有常见的string函数。 【本节目标】 1. 认识 String 类 2. 了解 String 类的基本用法 3. 熟练掌握 String 类的常见操作 4. 认识字符串常量池 5. 认识 …...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了  先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...
基于SpringBoot在线拍卖系统的设计和实现
摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...
华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...
