1. 程式人生 > >Linux程序的睡眠和喚醒

Linux程序的睡眠和喚醒

在Linux作業系統中,核心的穩定性至關重要,為了避免在Linux作業系統核心中出現無效喚醒問題,
Linux核心在需要程序睡眠的時候應該使用類似如下的操作:
/* ‘q’是我們希望睡眠的等待佇列 */
DECLARE_WAITQUEUE(wait,current);
add_wait_queue(q, &wait);
set_current_state(TASK_INTERRUPTIBLE);
/* 或TASK_INTERRUPTIBLE */
while(!condition) /* ‘condition’ 是等待的條件*/
schedule();
set_current_state(TASK_RUNNING);
remove_wait_queue(q, &wait);
上面的操作,使得程序通過下面的一系列步驟安全地將自己加入到一個等待佇列中進行睡眠:首先調
用DECLARE_WAITQUEUE()建立一個等待佇列的項,然後呼叫add_wait_queue()把自己加入到等待佇列中,並且將程序的狀態設 置為TASK_INTERRUPTIBLE或者TASK_INTERRUPTIBLE。然後迴圈檢查條件是否為真:如果是的話就沒有必要睡眠,如果條件不 為真,就呼叫schedule()。當程序檢查的條件滿足後,程序又將自己設定為TASK_RUNNING 並呼叫remove_wait_queue()將自己移出等待佇列。
從上面可以看到,Linux的核心程式碼維護者也是在程序檢查條件之前就設定程序的狀態為睡眠狀態,
然後才迴圈檢查條件。如果在程序開始睡眠之前條件就已經達成了,那麼迴圈會退出並用set_current_state()將自己的狀態設定為就緒,這樣同樣保證了程序不會存在錯誤的進入睡眠的傾向,當然也就不會導致出現無效喚醒問題。
下面讓我們用linux
 核心中的例項來看看Linux 核心是如何避免無效睡眠的,這段程式碼出自Linux2.6的核心(linux-2.6.11/kernel/sched.c: 4254):
4253 /* Wait for kthread_stop */
4254 set_current_state(TASK_INTERRUPTIBLE);
4255 while (!kthread_should_stop()) {
4256 schedule();
4257 set_current_state(TASK_INTERRUPTIBLE);
4258 }
4259 __set_current_state(TASK_RUNNING);
4260 return 0;
上面的這些程式碼屬於遷移服務執行緒migration_thread,這個執行緒不斷地檢查kthread_should_stop(),
直到kthread_should_stop()返回1它才可以退出迴圈,也就是說只要kthread_should_stop()返回0該程序就會一直 睡眠。從程式碼中我們可以看出,檢查kthread_should_stop()確實是在程序的狀態被置為TASK_INTERRUPTIBLE後才開始執 行的。因此,如果在條件檢查之後但是在schedule()之前有其他程序試圖喚醒它,那麼該程序的喚醒操作不會失效。

小結