在软件工程中,忙碌等待(也称自旋;英语:Busy waiting、busy-looping、spinning)是一种以进程反复检查一个条件是否为真为根本的技术,条件可能为键盘输入或某个锁是否可用。忙碌等待也可以用来产生一个任意的时间延迟,若系统没有提供生成特定时间长度的方法,则需要用到忙碌等待。不同的计算机处理器速度差异很大,特别是一些处理器设计为可能根据外部因素(例如操作系统上的负载)动态调整速率。因此,忙碌等待这种时间延迟技术容易产生不可预知、甚至不一致的结果,除非实现代码来确定处理器执行“什么都不做”循环的速度,或者循环代码明确检查实时时钟。
在某些情况下,忙碌等待是有效的策略,特别是实现自旋锁设计的操作系统上运行对称多处理。不过一般来说,忙碌等待是应该避免的反模式,处理器时间应该用来执行其他任务,而不是浪费在无用的活动上。
对于多核CPU,忙碌等待的优点是不切换线程,避免了由此付出的代价。因此一些多线程同步机制不使用切换到内核态的同步对象,而是以用户态的自旋锁或其派生机制(如轻型读写锁)来做同步,付出的时间复杂度相差3个数量级。忙碌等待可使用一些机制来降低CPU功耗,如Windows系统中调用YieldProcessor,实际上是调用了SIMD指令_mm_pause。
以下的C语言程序示范二个线程共享一个全局变量i,第一个线程用忙碌等待来确认变量i的值是否有改变。
1 #include <stdio.h> 2 #include <pthread.h> 3 #include <unistd.h> 4 #include <stdlib.h> 5 6 volatile int i = 0; /* i is global, so it is visible to all functions. 7 It's also marked volatile, because it 8 may change in a way which is not predictable by the compiler, 9 here from a different thread. */10 11 /* f1 uses a spinlock to wait for i to change from 0. */12 static void *f1(void *p) {13 while (i == 0) {14 /* do nothing - just keep checking over and over */15 }16 printf("i's value has changed to %d.\n", i);17 return NULL;18 }19 20 static void *f2(void *p) {21 sleep(60); /* sleep for 60 seconds */22 i = 99;23 printf("t2 has changed the value of i to %d.\n", i);24 return NULL;25 }26 27 int main() {28 int rc;29 pthread_t t1, t2;30 rc = pthread_create(&t1, NULL, f1, NULL);31 if (rc != 0) {32 fprintf(stderr, "pthread f1 failed\n");33 return EXIT_FAILURE;34 }35 rc = pthread_create(&t2, NULL, f2, NULL);36 if (rc != 0) {37 fprintf(stderr, "pthread f2 failed\n");38 return EXIT_FAILURE;39 }40 pthread_join(t1, NULL);41 pthread_join(t2, NULL);42 puts("All pthreads finished.");43 return 0;44 }