EidosOS实现(3)-等待与唤醒理论说明

Posted by WHX on April 1, 2026

EidosOS实现之任务的等待与唤醒理论说明

1、摘要

​ 本文介绍实时操作系统(RTOS)的核心机制之一——等待与唤醒机制。

​ 对于一个最小RTOS而言,需要解决两个基本问题:一是“下一个运行的是谁”,即调度器;二是“哪些任务需要等待,以及何时被重新唤醒”,即等待与唤醒机制。前一问题已在任务切换中讨论,本文将重点分析后者。

​ 在没有等待机制的情况下,最直接的方式是忙等待(busy wait),但这种方式会导致CPU资源被严重浪费。类似的问题在IO系统的发展过程中早已出现,并通过中断等机制得到解决。RTOS中的任务等待,本质上与此类问题具有相同结构。

​ 因此,本文将从忙等待的问题出发,结合IO系统中“等待机制”的演进,分析RTOS为何需要引入阻塞与唤醒机制,并基于中断思想构建任务级的等待与唤醒模型。

​ 在此基础上,可以进一步理解信号量、互斥量以及事件等同步机制的设计来源。这些机制虽然形式不同,但本质上都是对“任务等待关系”的不同表达方式。

​ 从这一角度看,等待与唤醒不仅是RTOS实现中的关键机制,更是理解其整体结构的核心切入点。

2、CPU忙等待的性能劣势

​ 上一篇任务切换实现完成后,现在的任务确实可以调度和切换,但它们无法高效的协作执行。举例来说,假设有三个任务A、B、C,它们都需要处理同一个资源,每个任务每次调度有10个时间片,而每个任务操作完需要30个时间片。当有任务操作资源时,其他任务不得执行操作,需要等待。那么目前的系统只能通过全局变量标志位来判断是否有任务操作资源。

uint32_t usedFlag;

void TaskA()
{
	while(1)
	{
		if(usedFlag)
        {
            
        }else
        {
            usedFlag = 1;
            operatorA();
            usedFlag = 0;
        }
	}
}
void TaskB()
{
	while(1)
	{
        if(usedFlag)
        {
            
        }else
        {
            usedFlag = 1;
            operatorB();
            usedFlag = 0;
        }
	}
}
void TaskA()
{
	while(1)
	{
        if(usedFlag)
        {
            
        }else
        {
            usedFlag = 1;
            operatorC();
            usedFlag = 0;
        }
	}
}

​ 假设三个任务优先级一样,那么每次有任务执行操作时,任务切换调度到其他任务时,需要CPU空转10个时间片,所以完成一次操作需要3*30=90个时间片,而理论上只需要30个时间片即可。这就是忙等待造成的CPU利用率低的问题。当等待的任务变多时,等待成为了系统性能的瓶颈。

​ 在上述例子中,当任务处于忙等待时,仍然占据CPU的使用权,无法出让;高优先级任务即使抢占到CPU使用权而由于资源无法使用而陷入忙等待,于是就违背了高优先级抢占的核心思想。总之忙等待不仅使得CPU效率变低,而且违背了RTOS多任务设计的初衷——当任务无法满足执行条件时,应该主动出让,而不是占用资源等待。

​ 那么,如何高效执行呢?我们需要一种机制使得任务在不满足条件执行时进行“休眠”,在满足条件时唤醒执行。

3、IO的等待演进历程

​ 忙等待的问题并不是在RTOS中特有的,在计算机另一重要领域——IO系统中,这一问题同样存在并更早的暴露出来。

​ 在早期CPU操作IO的时候,CPU通过轮询IO状态来确定IO是否准备完成,但在这期间,CPU处于忙等待操作,而且因为IO总线速度较慢,于是CPU忙等待IO的问题亟待解决。

​ 为了解决这一问题,引入了中断机制,CPU操作IO后不再需要轮询IO状态,而是再操作IO后直接去处理其他任务,当IO操作完成后经过中断通知CPU进行处理。这一机制将主动等待转变为被动通知,极大提高了CPU的利用率。

​ 在进一步优化过程中,利用DMA进行IO与内存的数据传输,CPU只需要开始和结束的时候进行处理,比中断带来更小的开销。当被动通知的思路没有变化。

​ 在IO系统中,演进的核心是中断机制中的从主动等待到被动通知,本质是一种等待思路的转变。

​ 在RTOS任务中的等待,与IO系统中的等待本质上是相同的。只是等待的条件不同。所以从IO系统的中断中的等待思想可以自然的推广到RTOS的任务调度中,从而形成RTOS的等待和唤醒机制。

4、RTOS等待唤醒机制

​ 在RTOS中通过阻塞-唤醒机制来解决忙等待的问题,实现被动通知的等待。当任务所需执行条件未满足时,主动释放CPU使用权而进入阻塞;当执行条件满足时,由系统将其重新唤醒,让其重新进入就绪状态参与调度。与忙等待不同,这种等待方式不再占用CPU资源,而是将执行权交还给调度器,允许其他任务执行。

​ 任务的执行条件都有哪些呢?有可能是某个资源可以利用,某个任务执行完成,或者某个事件的发生。条件分类很多,我们可以将其统称为事件。至此,我们就可以把RTOS的任务等待抽象成一种任务围绕事件的等待和唤醒模型,不同的同步机制,本质上是对这一模型的不同封装实现。

这里过早的抽象成事件,其实在信号、互斥量、队列等操作核心其实就是事件的等待和唤醒,只不过它们的判断条件不同。后面具体实现中,会先给出具体的不同机制的实现,然后抽象变成基于事件实现的方式。

5、总结与展望

​ 从忙等待到中断机制,再到RTOS的等待和唤醒机制,核心问题不在于实现方式,而在于系统学会了在“条件不足时停止任务的执行,条件满足时唤醒任务执行”,学会了不在主动等待而占据CPU资源,而是主动出让给调度器,让其他任务可以执行。这一过程中,可以将条件是否满足统一抽象为“事件”。任务不再关系具体资源,而是围绕事件进行等待和唤醒。在这一抽象机制之上,可以构建出多种不同的同步机制。例如信号量、互斥量以及事件标志组等。这些机制在形式上不同,但本质上都是对“等待和唤醒关系”的不同表达。