十、什么是临界资源及如何访问临界资源

时间:2025-03-14 13:42:56

文章目录

  • 1、什么是临界资源?
  • 2、什么是临界区?
  • 3、临界资源访问的两种方法
    • (1)关闭中断:避免了其他任务和中断来破坏,即这时候中断和任务调度无法正常进行
      • 1)在任务中屏蔽中断
      • 2)在中断服务函数中屏蔽中断
      • 3)补充说明
      • 4)为什么关闭中断也使任务调度停止了?——因为任务调度依赖于systick中断
    • (2)关闭调度器:避免了其他任务破坏,但这时候中断还是可以发生和处理的
  • 4、如果没有使用临界区后果会如何?
    • (1)应用任务的优先级比初始任务高时
    • (2)应用任务的优先级和初始任务一样时
    • (3)应用任务的优先级比初始任务低时

1、什么是临界资源?

临界资源是一次仅允许一个进程使用的共享资源。通俗可以理解为同一时刻只能由一个进程进行访问的资源。

2、什么是临界区?

每个进程中访问临界资源的那段代码称为临界区(Critical Section)。即是一段不能被打断的代码段
即保护了关键代码的执行不被打断,但也会影响系统的实时,任何使用了操作系统的中断响应都不会比裸机快。
每次只准许一个进程进入临界区,进入后不允许其他进程进入。

3、临界资源访问的两种方法

FreeRTOS中提供读写队列等API函数内部,均进行了临界资源的访问(即不会被其他事情干扰),在任务中如果不想使用队列等并且也不想被其他事情打扰均可参考这种进入临界区的做法。

(1)关闭中断:避免了其他任务和中断来破坏,即这时候中断和任务调度无法正常进行

在FreeRTOS提供的读写队列、信号量、互斥量等API函数里面,均实现了临界区的访问,其采用的均是关闭中断的方法来进行临界区的访问。
那么问题来了——这个关闭中断是关闭了所有中断吗?
答案很显然,肯定不是了,它关闭的只是部分优先级较低的中断。FreeRTOS为什么这样操作和在代码上如何做的在后面中断管理的博客中会详细说说。

进行临界资源访问的时候,这些API函数都是成对出现的,即有进入临界区的API函数,也有退出的。具体如下

1)在任务中屏蔽中断

/* 在任务中,当前时刻中断是使能的
* 执行这句代码后,屏蔽中断
*/
taskENTER_CRITICAL();
/* 访问临界资源 */
/* 重新使能中断 */
taskEXIT_CRITICAL();

2)在中断服务函数中屏蔽中断

{
 /* 用来记录当前中断是否使能 */
 UBaseType_t uxSavedInterruptStatus;
 
 /* 在 ISR 中,当前时刻中断可能是使能的,也可能是禁止的
 * 所以要记录当前状态, 后面要恢复为原先的状态
 * 执行这句代码后,屏蔽中断
 */
 uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
 
 /* 访问临界资源 */
 /* 恢复中断状态 */
 taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
 /* 现在,当前 ISR 可以被更高优先级的中断打断了 */
}

3)补充说明

taskENTER_CRITICA()/taskEXIT_CRITICAL()之间和taskENTER_CRITICA_FROM_ISR()/taskEXIT_CRITICAL_FROM_ISR()之间:
a)低优先级的中断被屏蔽了:即优先级低于、等于configMAX_SYSCALL_INTERRUPT_PRIORITY
b)高优先级的中断可以产生:优先级高于configMAX_SYSCALL_INTERRUPT_PRIORITY

4)为什么关闭中断也使任务调度停止了?——因为任务调度依赖于systick中断

(2)关闭调度器:避免了其他任务破坏,但这时候中断还是可以发生和处理的

在事件组的相关API函数内部进入临界区的方法均是采用关闭调度器的方法

/* 暂停调度器 */
void vTaskSuspendAll( void );
/* 恢复调度器
* 返回值: pdTRUE 表示在暂定期间有更高优先级的任务就绪了
* 可以不理会这个返回值
*/
BaseType_t xTaskResumeAll( void );

4、如果没有使用临界区后果会如何?

(1)应用任务的优先级比初始任务高时

创建完应用任务后会立马去执行优先级最高的任务,当其被阻塞时回到初始任务继续创建任务,直至应用任务创建完成,最后把自己(初始任务)删除。

(2)应用任务的优先级和初始任务一样时

创建完应用任务后根据任务的时间片来执行,直到所有应用任务创建完成,最后初始任务把自己删除。

(3)应用任务的优先级比初始任务低时

创建完应用任务后不会被执行,除非优先级和上述两种情况一样,直到所有应用任务创建完成,最后初始任务把自己删除。