简介
每个进程中访问临界资源的那段代码称为临界区(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();
}
- 如果一段临界区太长而不适合简单的关中断来实现,可以考虑采用挂起调度器的方式
- 唤醒调度器是一个相对较长的操作
注意
在使用临界区时,一般不允许其运行时间过长,只要进入临界区的线程还没有离开,其他所有试图进入此临界区的线程都会被挂起而进入到等待状态,并会在一定程度上影响程序的运行性能