一、基本概念

同步与互斥是多任务/多线程编程中的两个核心机制:

  • 同步:指多个任务之间存在明确的先后顺序,一个任务必须等待另一个任务完成某些操作后才能继续执行。

  • 互斥:指多个任务在同一时刻争抢使用同一资源(临界资源),必须通过某种机制保证同一时间只有一个任务可以使用该资源。


二、线程安全问题的由来

问题描述

当多个任务同时访问一个共享资源(如全局变量)时,如果没有适当的保护机制,就会出现数据不一致的问题。

示例分析:全局变量 count++

c

int count = 0;
// 两个线程同时执行 count++

count++ 实际上包含三个步骤(非原子操作):

  1. 读取 count 的值到寄存器

  2. 对寄存器中的值加 1

  3. 将结果写回 count 的内存地址

执行流程(可能出现的问题):

  1. 线程 A 读取 count = 0,准备加 1;

  2. 此时切换到线程 B,也读取 count = 0,完成加 1 并写回,count 变为 1;

  3. 切换回线程 A,继续执行加 1(基于之前读到的 0),写回后 count 仍为 1。

预期结果为 2,实际结果为 1,这就是典型的线程安全问题,也称为数据竞争


三、同步机制的缺陷

  • 使用同步机制(如忙等待)会导致任务死等,浪费 CPU 资源。

  • 应避免使用 while() 循环进行无意义的等待,而应使用阻塞机制让出 CPU。


四、全局变量在 RTOS 中的存储位置

问题:全局变量存储在哪个栈中?

答案:全局变量不属于任何一个任务的栈。

内存区域划分:

  1. 代码区 (Text Segment):存放程序指令。

  2. 全局/静态数据区 (Data/BSS Segment)

    • 存放全局变量静态变量

    • 在程序启动时分配,生命周期贯穿整个程序;

    • 被所有任务和中断共享。

  3. 堆区 (Heap):动态分配的内存(如 malloc / pvPortMalloc)。

  4. 栈区 (Stack)

    • 主栈/中断栈:用于 ISR 和内核调度;

    • 任务栈:每个任务独立拥有,用于存放局部变量和上下文。

结论:

全局变量存储在全局数据区,是共享资源,访问时需使用临界区、信号量、互斥锁等机制进行保护。


五、volatile 关键字的作用

问题背景:

在编译器优化的情况下,可能会将变量缓存在寄存器中,导致多任务环境中读取到旧值

示例代码(无 volatile):

c

int g_calc_end = 0;// Writer 任务
void vWriterTask(void *pvParameters) {while(1) {g_calc_end = 1; // 修改全局变量}
}// Reader 任务
void vReaderTask(void *pvParameters) {while(1) {if (g_calc_end == 1) { // 判断全局变量// 执行操作g_calc_end = 0;}vTaskDelay(1);}
}

问题流程:

  1. Reader 任务第一次读取 g_calc_end 到寄存器;

  2. 编译器优化后,后续判断直接使用寄存器中的值(不再从内存读取);

  3. Writer 任务修改了内存中的 g_calc_end

  4. Reader 任务仍然使用寄存器中的旧值,导致判断错误。

解决方案:使用 volatile

c

volatile int g_calc_end = 0;

volatile 的作用:

  • 告诉编译器该变量是“易变的”;

  • 禁止对其进行优化:

    • 每次读取必须从内存中重新加载;

    • 每次写入必须立即写回内存。


六、补充与总结

疏漏补充:

  1. 原子操作:某些架构提供原子指令(如 __atomic_inc),可避免数据竞争;

  2. 临界区保护:使用开关中断、调度器锁、互斥量等方法保护共享资源;

  3. 任务通信机制:除了全局变量,还可使用队列、事件组、信号量等进行任务间同步与通信;

  4. 内存屏障:在多核系统中,可能需要使用内存屏障指令确保内存访问顺序。

总结图示:

(见原笔记中的图片,图示展示了同步与互斥的机制和资源访问流程)


七、最佳实践建议

  1. 尽量避免使用全局变量,优先使用 RTOS 提供的通信机制;

  2. 若必须使用共享资源,务必使用互斥锁或信号量进行保护;

  3. 对于可能被异步修改的变量,必须使用 volatile 声明;

  4. 在临界区中尽量减少操作时间,避免影响系统实时性;

  5. 合理使用任务阻塞机制,避免忙等待浪费 CPU 资源。

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

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

相关文章

Tomcat 启动流程与类加载机制

Tomcat 启动流程与类加载机制1. 引言 Tomcat 的启动不仅仅是简单的 java -jar 或 catalina.sh start。 它背后包含 Bootstrap 启动器、Catalina 控制器、Server/Service/Connector/Container 初始化 等关键步骤。 另一方面,Tomcat 为了支持 热部署、不同应用间类隔离…

MTK Linux Charger驱动分析(十二)- mtk_pd_adapter.c

1. 代码整体分析 mtk_pd_adapter.c(源文件) 主要内容: 该文件实现了MediaTek平台的USB PD(Power Delivery)适配器驱动,基于Linux内核的电源管理和Type-C端口控制器(TCPC)框架。 它处理PD协议事件,包括PD连接状态、Type-C状态、水检测(WD_STATUS)、Sink VBUS变化等。…

Spring Boot Logback 日志配置详解:从基础到分布式追踪

日志是应用程序不可或缺的组成部分,它不仅能帮助我们调试问题,还能监控系统运行状态。在 Spring Boot 生态中,Logback 凭借其高性能和灵活性成为首选的日志框架。本文将通过一个实际的 Logback 配置文件,详细解析其各个组件的功能…

软件体系结构——后端三层架构

三层架构——Controller、Service、Dao 不仅是对代码进行的逻辑分层。其真正的本质,是将业务、技术和数据剥离。搞业务的专心做业务,搞技术的专心搞技术,做数据存储的专心做数据存储。三方通过接口进行对接,任一部分重构&#xff…

QML学习笔记(一)基本了解和工程配置

前言: 已经从事QT开发几年了,但对于QML这个东西始终是没有彻底掌握,一方面实际工作中没有用到过,其次它的语法对我来说是全新的东西,不像QWidget那一套可以直接在C中去写。这就是为什么网上都说qml更简单,我…

SAP HANA Scale-out 04:缓存

结果缓存静态结果缓存 Vs 动态结果缓存FeatureStatic Result CacheDynamic Result CacheTarget Scenario对复杂视图(通常是顶层视图)的查询频繁更新的大表(例如ACDOCA)上的聚合查询Query result非实时数据实时数据ScopeTarget obj…

嘉兴禾润 HTR7216 (S) LED 驱动芯片:特性与应用

在如今智能设备飞速普及的时代,无论是智能家居的氛围营造、IoT 设备的状态提示,还是个人消费电子的视觉呈现,都离不开高性能 LED 驱动芯片的支撑。嘉兴禾润推出的 HTR7216 (S) LED 驱动芯片,凭借丰富的功能、精准的控制以及出色的…

Python实现剑龙优化算法 (Stegosaurus Optimization Algorithm, SOA)优化函数(付完整代码)

Python实现剑龙优化算法 (Stegosaurus Optimization Algorithm, SOA)优化函数(付完整代码)1.剑龙优化算法介绍剑龙优化算法(Stegosaurus Optimization Algorithm,SOA)是一种受剑龙独特生理结构和行为模式启发而设计的元…

分布式拜占庭容错算法——权益证明(PoS)算法详解

Java 实现权益证明(PoS)算法详解 一、PoS 核心机制 #mermaid-svg-Sbj0HU6MjOl1yo5L {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Sbj0HU6MjOl1yo5L .error-icon{fill:#552222;}#mermaid-s…

【论文阅读】谷歌:生成式数据优化,只需请求更好的数据

谷歌DeepMind团队通过Generative Data Refinement(GDR)技术,成功将极端有毒的4chan讨论数据转化为安全且语义丰富的训练素材,推动了LLM训练数据净化的新范式: • GDR利用预训练大模型对原始数据进行“重写”&#xff0…

C++ 多线程实战 10|C++20 的信号量、闩锁与屏障

目录 前言 学习目标 1. 信号量(Semaphore) 示例:限制并发下载任务 2. 闩锁(Latch) 示例:赛跑 3. 屏障(Barrier) 示例:图像处理流水线 4. 常见坑与对策 5. 实践作…

【Java SE】01. 初识Java

1. 认识Java Java是一种优秀的程序设计语言,它具有令人赏心悦目的语法和易于理解的语义。Java还是一个有一系列计算机软件和规范形成的技术体系,这个技术体系提供了完整的用于软件开发和跨平台部署的支持环境,并广泛应用于嵌入式系统、移动终…

解锁仓储智能调度、运输路径优化、数据实时追踪,全功能降本提效的智慧物流开源了

AI 视频监控平台:全链路协同驱动的智能监控解决方案AI 视频监控平台是一款融合高性能功能与轻量化操作的实时算法驱动型视频监控系统,其核心愿景在于深度破除不同芯片厂商间的技术壁垒,省去冗余重复的适配环节,最终达成芯片、算法…

冒泡排序与选择排序以及单链表与双链表

1. 冒泡排序(Bubble Sort) 1. 原理 冒泡排序是一种 简单的排序算法,通过 两两比较相邻元素,把较大的元素逐渐 “冒泡” 到数组末尾。 思路: 从数组头开始,比较相邻两个元素。 如果前一个比后一个大&…

Python实现计算点云投影面积

本次我们分享一种基于 Open3D 的快速、稳健方法,用于从激光点云中自动提取“地面”并计算其投影面积。算法先自适应估计地面高程,再将地面点投影至水平面,随后用凸包或最小外接矩形求取面积。整个流程无需人工干预,单文件即可运行…

AXI4 协议

一、AXI4简介AXI4(Advanced eXtensible Interface 4)是ARM公司推出的高性能片上总线协议,属于AMBA(Advanced Microcontroller Bus Architecture)标准的一部分。它专为高带宽、低延迟的片上通信设计,广泛应用…

《饿殍:明末千里行》Switch版试玩发布 3月13日发售

使用jQuery的常用方法与返回值分析 jQuery是一个轻量级的JavaScript库,旨在简化HTML文档遍历和操作、事件处理以及动画效果的创建。本文将介绍一些常用的jQuery方法及其返回值,帮助开发者更好地理解和运用这一强大的库。 1. 选择器方法 jQuery提供了多种…

[特殊字符] 认识用户手册用户手册(也称用户指南、产品手册)是通过对产品功能的清

一份优秀的用户手册能有效降低用户的使用门槛,提升用户体验和工作效率。下面我将为你梳理编写用户手册的核心要点、步骤和技巧。📖 认识用户手册用户手册(也称用户指南、产品手册)是​​通过对产品功能的清晰解释,为特…

苹果软件代码混淆,iOS混淆、iOS加固、ipa安全与合规取证注意事项(实战指南)

在移动软件交付与合规审计中,苹果软件代码混淆已成为保护知识产权与用户数据的常规手段。但混淆带来的不仅是逆向难度的提升,也会触发崩溃取证、符号化(symbolication)、审计合规与法律证据保存等问题。本文从工程与合规双视角出发…