在
软件工程中,忙碌等待是一种以
进程反复检查一个条件是否为真为根本的技术,条件可能为
键盘输入或某个锁是否可用。忙碌等待也可以用来产生一个任意的时间延迟,若系统没有提供生成特定时间长度的方法,则需要用到忙碌等待。不同的
计算机处理器速度差异很大,特别是一些
处理器设计为可能根据外部因素(例如
操作系统上的负载)动态调整速率。因此,忙碌等待这种时间延迟技术容易产生不可预知、甚至不一致的结果,除非实现代码来确定处理器执行“什么都不做”循环的速度,或者循环代码明确检查
实时时钟。
忙碌等待是
进程反复检查一个条件是否为真的技术,如
键盘输入是否可用。忙碌等待也可以用来生成一个任意的时间延迟,这一技术对于一无法产生特定时间长度方法的系统是必要的。从计算机间的传输速度和
计算机处理器速度差异很大,特别是一些
处理器根据外部因素设计动态调整速度,如操作系统上的负载。因此,忙碌等待延迟技术往往产生不可预知的甚至不一致的结果,除非编程来确定如何确定处理器可以执行“无所作为”的速度。
在某些情况下,忙碌等待是有效的策略,特别是实现
自旋锁设计的
操作系统上运行
对称多处理。不过一般来说,忙碌等待是应该避免的反模式,处理器时间应该用来执行其他
任务,而不是浪费在无用的活动上。
对于多核CPU,忙碌等待的优点是不切换线程,避免了由此付出的代价。因此一些
多线程同步机制不使用切换到内核态的同步对象,而是以用户态的自旋锁或其派生机制(如轻型
读写锁)来做同步,付出的时间复杂度相差3个数量级。忙碌等待可使用一些机制来降低CPU功耗,如Windows系统中调用YieldProcessor,实际上是调用了
SIMD指令_mm_pause。
以下的
C语言程序示范二个线程共享一个全域
变量i,第一个线程用忙碌等待来确认变量i的值是否有改变。
大多数操作系统和线程库提供了各种各样可以阻止事件过程的
系统调用,如锁获取、计时器变化,I/O可用性或信号。使用系统调用来产生延迟会有最简单、最有效、公平且没有
竞争危害的结果。一个调用会检查、通知事件等待的调度程序,插入一个适用的记忆障碍,也可以在返回之前执行所请求的I / O操作。当调用者被堵住时,其他进程可以使用CPU。调度器有实现
优先级继承所需的信息或其他机制,来避免资源衰竭的问题。
在大部分操作系统中,也可以在忙碌等待中加入延迟函数(sleep()),以减少忙碌等待浪费的CPU资源。这可以让线程暂停指定的时间,在此期间线程不会浪费CPU时间。如果循环检查只是检查一些简单的事务,将大部分时间花费在延迟函数,则不太会浪费太多CPU时间。
若程序永远不会结束(如操作系统),可以通过无条件跳转(例如
NASM语法中的jmp $)实现无限次的忙碌等待。CPU会永远无条件跳转到程序正在运行到的位置。因此可以用以下的程序取代忙碌等待:
一些底层编程中可能需要用到需忙碌等待。对每个
硬件设备(尤其是偶尔才使用到的硬件)设置
中断可能不切实际甚至不可能。有时需要将某种的控制数据写入硬件,在写入后获取设备状态,但状态可能要在写入后数个机器周期后才有效。
程序员可以调用操作系统延迟函数,不过这样做可能要耗费更多的时钟周,此时就可以使用忙碌等待。