[FreeRTOS] 临界区处理

简介

每个进程中访问临界资源的那段代码称为临界区(Critical Section)临界资源是一次仅允许一个进程使用的共享资源)。
每次只准许一个进程进入临界区,进入后不允许其他进程进入。不论是硬件临界资源,还是软件临界资源,多个进程必须互斥地对它进行访问。
多个进程中涉及到同一个临界资源的临界区称为相关临界区

程序调度法则

进程进入临界区的调度原则是:

1. 如果有若干进程要求进入空闲的临界区,一次仅允许一个进程进入。
2. 任何时候,处于临界区内的进程不可多于一个。如已有进程进入自己的临界区,则其它所有试图进入临界区的进程必须等待。
3. 进入临界区的进程要在有限时间内退出,以便其它进程能及时进入自己的临界区。
4. 如果进程不能进入自己的临界区,则应让出CPU,避免进程出现“忙等”现象。

FreeRTOS解决方法

开关中断

void process_data(void)
{
    taskENTER_CRITICAL(); //or portENTER_CRITICAL();
    x++;
    taskEXIT_CRITICAL();  //or portEXIT_CRITICAL();
}
  • 抢占式上下文切换只可能在某个中断完成,所以调用taskENTER_CRITICAL()的任务可以在中断关闭的时段一直保持运行态,直到退出临界区
  • 临界区必须只具有很短的时间,否则会影响中断响应时间

使用信号量或者互斥量

推荐使用互斥量,因为互斥量解决了优先级翻转的问题

void process_data(void)
{
    if(xSemaphoreTake(xSemaphore, 10) == pdTRUE)
    {
        x++;
        xSemaphoreGive( xSemaphore );
    }
}

信号量和互斥量的最大区别是

  • 用于互斥的信号量必须归还
  • 用于同步的信号量在完成同步后变丢弃,不需要归还

禁止任务调度

void process_data(void)
{
    vTaskSuspendAll();
    x++;
    xTaskResumeAll();
}
  • 如果一段临界区太长而不适合简单的关中断来实现,可以考虑采用挂起调度器的方式
  • 唤醒调度器是一个相对较长的操作

注意

在使用临界区时,一般不允许其运行时间过长,只要进入临界区的线程还没有离开,其他所有试图进入此临界区的线程都会被挂起而进入到等待状态,并会在一定程度上影响程序的运行性能

Good Good Study! Day Day Up!

原文地址:https://www.cnblogs.com/kdurant/p/4190216.html