1. 什么是忙等待?

忙等待(Busy Waiting),也被称为“自旋(Spinning)”或“忙循环(Busy Loop)”,是一种进程同步机制。在这种机制下,一个进程会持续检查某个条件是否满足,以决定是否继续执行。例如,它可能在等待某个锁(lock)或资源是否可用。

举个例子:假设一个进程需要访问某个资源,但该资源当前正被其他进程占用。此时,这个进程不会进入休眠状态,而是不断循环检查资源是否释放。这种持续检查的行为就是“忙等待”。

如下图所示,进程在等待期间持续占用CPU资源:

Busywaiting

操作系统中常见的两种等待方式如下:

忙等待:进程持续检查条件,期间持续占用CPU资源。
阻塞等待(Sleep Waiting):进程进入休眠状态,等待条件满足后被唤醒,期间不占用CPU资源。

2. 忙等待的使用场景

忙等待通常用于实现互斥(Mutual Exclusion)。互斥机制确保多个进程不会同时访问共享资源,从而避免竞争条件(Race Condition)。

在互斥机制中,进程在进入临界区(Critical Section)时必须获得资源的独占访问权限。此时如果资源已被占用,进程可以选择忙等待,直到资源释放。

3. 忙等待的缺点

虽然实现简单,但忙等待存在以下明显问题:

  • 资源浪费:进程持续检查条件会浪费CPU资源。
  • 系统效率下降:低优先级任务占用CPU时间,而高优先级任务无法及时执行。
  • 不适合长时间等待:若等待时间较长,忙等待会严重影响系统性能。

3.1 解决方案一:使用延迟函数(Sleep)

大多数操作系统采用“延迟函数”来缓解忙等待带来的资源浪费问题。延迟函数会将进程置为休眠状态一段时间,期间不占用CPU资源。例如:

algorithm delay(process p, resource z):
    // INPUT
    //   p = 需要延迟的进程
    //   z = 进程正在等待的资源
    // OUTPUT
    //   将进程 p 置于休眠状态,直到资源 z 可用

    while z is still in use:
        p.sleep(900)

进程休眠后会在指定时间被唤醒。若资源仍未可用,可逐步增加休眠时间,直到条件满足。

3.2 解决方案二:使用信号量(Semaphore)阻塞进程

另一种更高效的方式是使用信号量(Semaphore)机制。进程在等待时被放入等待队列,不占用CPU资源。当资源可用时,系统将其唤醒并放入就绪队列。

这种方式避免了忙等待的资源浪费问题,是大多数现代操作系统推荐的做法。

4. 忙等待的优点

尽管存在资源浪费问题,但在某些特定场景下,忙等待仍具有一些优势:

实现简单:逻辑清晰,易于理解和实现。
适用于短时间等待:如果等待时间非常短,忙等待的开销可以忽略不计。
适合用于自旋锁(Spinlock):在并发访问资源较少的系统中,Spinlock 可以提供高效的同步机制。

例如,自旋锁(Spinlock) 是一种常见的忙等待实现。它在多线程环境中用于确保对共享资源的互斥访问。当资源不可用时,线程进入自旋状态,不断检查资源是否释放。一旦资源释放,线程立即恢复执行。

5. 总结

忙等待是一种简单但低效的同步机制。它适用于等待时间短、资源竞争不激烈的场景,但在大多数现代系统中,更推荐使用 sleep 或信号量机制来替代。

优点:实现简单,适合短时间等待,可用于自旋锁。
缺点:资源浪费严重,不适合长时间等待,影响系统性能。

在开发中,我们应根据具体场景选择合适的同步机制。合理使用忙等待可以提升性能,滥用则可能成为系统瓶颈


原始标题:What Does “Busy Waiting” Mean in Operating Systems?

« 上一篇: 汇编语言入门