三言两语聊Kernel:Busy Waiting or Sleeping?

在某些情况下,我们需要将当前线程的执行挂起,直至某一事件发生。这个事件可能是一个有争抢的资源变为可用,时间的流逝,或者锁的释放。这个等待可以通过两种基本的方式来实现:

  • Busy Waiting
  • Sleeping

系统通过在循环里面旋转并且不停的去检查问题事件是否发生来实现Busy Waiting。  
比如,如果我们想要等待5s,可以这样来实现:

1
2
3
const int until = get_time() + 5;
while(until > get_time())
;

这样做的好处是,它的实现较简单,并且如果不等太久它在性能上会表现很好,因为避免了切换到其他线程的开销。坏处也很明显:把CPU cycle浪费在执行无任何价值的东西上。    

Busy Waiting相对于Sleeping比较容易理解。

Sleeping通过更复杂的方式来实现:首先构造一个需要等待的线程的链表,叫作等待队列;接着把自己加入到等待队列中,控制权交给内核;然后当问题事件发生时让内核唤醒该链表里的一个(些)进程去执行。举例来说,你可能需要在某一个mutex变得可用时让内核唤醒你,于是把控制权交给内核,让内核去执行除你之外的进程,在该mutex变得可用时内核再去唤醒你。如下:

1
2
3
4
5
6
mutex_lock(&m_lock);
    list_add_tail(current, &m_lock->wait_list);
    schedule();

mutex_unlock(&m_lock);
    wake_up_process(m_lock.wait_list.next->task);

 Sleeping相对于Busy Waiting的好处是,内核可以在等待期间去执行有意义的事情。坏处则是它的开销:维护一个链表,让你自己去睡眠,上下文切换到一个新的进程(再加上切换回你自己)。如果等待的时间较短,显然使用Busy Waiting更合理。

Comments