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

[FreeRTOS- 野火] - - - 临界段

一、介绍

临界段最常出现在对一些全局变量进行操作的场景。

1.1 临界段的定义

临界段是指在多任务系统中,一段需要独占访问共享资源的代码。在这段代码执行期间,必须确保没有任何其他任务或中断可以访问或修改相同的共享资源。

临界段的主要目的是防止多个任务或中断同时访问共享资源,从而避免数据不一致或竞态条件。

1.2 临界段的特点

  • 1、互斥访问:

    • 临界段内的代码必须确保在任何时刻只有一个任务或中断可以访问共享资源。

    • 其他任务或中断必须等待,直到当前任务或中断完成对共享资源的访问。

  • 2、短小精悍:

    • 临界段的代码应该尽可能短小,以减少对系统性能的影响。

    • 长时间的临界段可能会导致系统响应延迟,影响实时性。

  • 3、明确的入口和出口:

    • 临界段必须有明确的入口和出口。

    • 入口处通常会禁用中断,出口处会恢复中断。

1.3 临界段的实现方式

在RTOS中,临界段可以通过以下几种方式实现:

  • 1、禁用中断:

    • 直接禁用所有中断:通过设置硬件寄存器(如Cortex-M的 PRIMASK)来禁用所有中断。

    • 设置中断优先级阈值:通过设置硬件寄存器(如Cortex-M的 BASEPRI)来屏蔽优先级高于某个值的中断。

  • 2、使用互斥量(Mutex):

    • 互斥量是一种同步原语,用于确保对共享资源的互斥访问。

    • 任务在访问共享资源前必须先获取互斥量,访问完成后释放互斥量。

// 创建互斥量
SemaphoreHandle_t xMutex = xSemaphoreCreateMutex();// 获取互斥量
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE)
{// 临界段代码
}// 释放互斥量
xSemaphoreGive(xMutex);
  • 3、使用信号量(Semaphore):

    • 信号量是一种计数器,用于控制对共享资源的访问。

    • 任务在访问共享资源前必须先获取信号量,访问完成后释放信号量。

// 创建信号量
SemaphoreHandle_t xSemaphore = xSemaphoreCreateBinary();// 获取信号量
if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE)
{// 临界段代码
}// 释放信号量
xSemaphoreGive(xSemaphore);
  • 4、使用自旋锁(Spinlock):

    • 自旋锁是一种简单的同步机制,任务在获取锁时会不断尝试,直到获取成功。

    • 自旋锁通常用于短时间的临界段,以减少上下文切换的开销。

二、Cortex-M内核快速关中断指令

为了快速地开关中断, Cortex-M 内核专门设置了一条 CPS 指令,有 4 种用法,具体如下:

CPSID I ;PRIMASK=1 ;	//关中断
CPSIE I ;PRIMASK=0 ;	//开中断
CPSID F ;FAULTMASK=1 ;	//关异常
CPSIE F ;FAULTMASK=0 ;	//开异常

在ARM Cortex-M系列处理器中,PRIMASK、FAULTMASK 和 BASEPRI 是三个用于控制中断和异常处理的系统级寄存器。

2.1 PRIMASK

  • 功能:禁用除NMI(不可屏蔽中断)和Hard Fault(硬件故障)之外的所有异常和中断。

  • 作用机制:设置 PRIMASK (通过 MSR PRIMASK, #1 或 CPSID I;)把当前中断优先级提为0,来屏蔽除NMI和Hard Fault之外的所有异常和中断。

  • 典型用途:用于快速进入临界区,保护关键代码段不被中断打断,例如在RTOS任务切换或共享资源访问等应用中。

  • 特点:简单易用,但对系统实时性影响较大,长时间开启可能导致高优先级中断无法响应。

是一个单一比特的寄存器。缺省值是0,表示没有关中断。

2.2 FAULTMASK

  • 功能:禁用除NMI之外的所有异常和中断,包括Hard Fault。

  • 作用机制:设置 FAULTMASK(通过MSR FAULTMASK, #1或CPSID F ;)会把当前中断优先级提升到-1,仅允许NMI。

  • 典型用途:在异常处理程序中临时屏蔽可能引发嵌套故障的操作(如内存访问)。

  • 特点:比PRIMASK更严格,可能影响系统稳定性,仅在特权模式(Privileged Mode)下可修改。

是一个只有1位的寄存器。缺省值是0,表示没有关异常。

2.3 BASEPRI

  • 功能:基于优先级的动态中断屏蔽,仅屏蔽优先级低于阈值的中断。

  • 作用机制:设置 BASEPRI (通过 MSR BASEPRI, #priority)允许优先级低于阈值的中断继续执行,高于阈值的中断被屏蔽。

  • 典型用途:灵活控制中断优先级,允许高优先级任务/中断优先执行,同时屏蔽低优先级中断。

  • 特点:更精细的控制,避免完全禁用所有中断,但需要合理设置优先级阈值,否则可能导致意外屏蔽。

三、关中断

关中断函数分为带返回值不带返回值两种。

3.1 不带返回值的关中断函数

static portFORCE_INLINE void vPortRaiseBASEPRI( void )		// 不带返回值的函数是不能嵌套的
{
uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;__asm{/* Set BASEPRI to the max syscall priority to effect a criticalsection. */msr basepri, ulNewBASEPRI			// 11 大于11的中断不能被响应 小于11则可以 根据 configMAX_SYSCALL_INTERRUPT_PRIORITY 的值来配置dsbisb}
}
  • dsb(Data Synchronization Barrier):数据同步屏障,确保所有之前的内存访问操作(如读写操作)都完成后再继续执行后续代码。
  • isb(Instruction Synchronization Barrier):指令同步屏障,确保所有之前的指令都执行完成后再继续执行后续代码。

3.2 带返回值的关中断函数

static portFORCE_INLINE uint32_t ulPortRaiseBASEPRI( void )		// 可嵌套
{
uint32_t ulReturn, ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;__asm{/* Set BASEPRI to the max syscall priority to effect a criticalsection. */mrs ulReturn, basepri					// 先将 basepri 的值保存在 返回值中msr basepri, ulNewBASEPRI			// 再设置 basepri 的值dsbisb}return ulReturn;
}

四、开中断

static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )
{__asm{/* Barrier instructions are not used as this function is only used tolower the BASEPRI value. */msr basepri, ulBASEPRI}
}

五、进入/退出临界段的宏

5.1 进入临界段的宏

5.1.1 不带中断保护

#define taskENTER_CRITICAL() portENTER_CRITICAL()	// task.h中定义#define portENTER_CRITICAL() vPortEnterCritical()	// portmacro.h中定义#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()	// portmacro.h中定义

5.1.2 带中断保护

#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()	// task.h 中定义#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI()	// portmacro.h 中定义

5.2 退出临界段的宏

5.2.1 不带中断保护

#define taskEXIT_CRITICAL() portEXIT_CRITICAL()		// task.h 中定义#define portEXIT_CRITICAL() vPortExitCritical()		// portmacro.h 中定义#define portENABLE_INTERRUPTS() vPortSetBASEPRI( 0 )	//portmacro.h 中定义

5.2.2 带中断保护

#define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x )	// task.h 中定义#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x)	//  portmacro.h 中定义

六、临界段代码的应用

在 FreeRTOS 中,对临界段的保护出现在两种场合,一种是在中断场合,一种是在非中断场合

6.1 中断场合

// 在中断场合,临界段可以嵌套
{uint32_t ulReturn;// 进入临界段,临界段可以嵌套ulReturn = taskENTER_CRITICAL_FROM_ISR();// 临界段代码// 退出临界段taskEXIT_CRITICAL_FROM_ISR( ulReturn );
}

6.2 非中断场合

// 非中断场合,临界段不能嵌套
{// 进入临界段taskENTER_CRITICAL();// 临界段代码// 退出临界段taskEXIT_CRITICAL();
}
http://www.xdnf.cn/news/723925.html

相关文章:

  • docker环境添加安装包持久性更新
  • plotbunni开源程序是具有 AI 辅助的 FOSS 小说写作套件
  • npm、pnpm、yarn使用以及区别
  • 使用Haproxy搭建web群集
  • ONLYOFFICE文档API:更强的安全功能
  • USB Network Gate的中国挑战者:软硬协同USB Server
  • Docker 笔记 -- 借助AI工具强势辅助
  • 【Android】如何抓取 Android 设备的 UDP/TCP 数据包?
  • ass字幕嵌入mp4带偏移
  • ubuntu系统安装Pyside6报错解决
  • Flask与PostgreSQL交互教程
  • K8s工作流程与YAML实用指南
  • 企业信息化集成方案:聚水潭·奇门数据对接金蝶云星空
  • 历年中国科学技术大学计算机保研上机真题
  • 无人机桥梁3D建模、巡检、检测的航线规划
  • 解决访问网站提示“405 很抱歉,由于您访问的URL有可能对网站造成安全威胁,您的访问被阻断”问题
  • 最悉心的指导教程——阿里云创建ECS实例教程+Vue+Django前后端的服务器部署(通过宝塔面板)
  • 使用 Zabbix 监控 MySQL 存储空间和性能指标的完整实践指南
  • OramaCore 是您 AI 项目、答案引擎、副驾驶和搜索所需的 AI 运行时。它包括一个成熟的全文搜索引擎、矢量数据库、LLM界面和更多实用程序
  • 编译rustdesk,使用flutter、hwcodec硬件编解码
  • 深度学习笔记25-RNN心脏病预测(Pytorch)
  • docker-compose搭建prometheus以及grafana
  • 工厂方法模式(Factory Method)深度解析:从原理到实战优化
  • 车辆减振器焊口疲劳试验台
  • powershell 中 invoke-expression 报错解决
  • 华为欧拉系统中部署FTP服务与Filestash应用:实现高效文件管理和共享
  • AsyncIOScheduler与BackgroundScheduler的线程模型对比
  • iOS 集成网易云信的音视频呼叫组件
  • leetcode:479. 最大回文数乘积(python3解法,数学相关算法题)
  • [Javascript进阶]JSON.stringify与JSON.parse详解