Linux程序休眠和喚醒

2021-06-18 02:51:23 字數 4279 閱讀 7663

當程序以阻塞的方式通訊,在得到結果前程序會掛起休眠。

為了將程序以一種安全的方式進入休眠,我們需要牢記兩條規則:

一、永遠不要在原子上下文中進入休眠。

二、程序休眠後,對環境一無所知。喚醒後,必須再次檢查以確保我們等待的條件真正為真

簡單休眠

完成喚醒任務的**還必須能夠找到我們的程序,這樣才能喚醒休眠的程序。需要維護乙個稱為等待佇列的資料結構。等待佇列就是乙個程序鍊錶,其中包含了等待某個特定事件的所有程序。

linux維護乙個「等待佇列頭」來管理,wait_queue_head_t,定義在

struct  __wait_queue_head ;

typedef  struct __wait_queue_head  wait_queue_head_t;

初始化方法:

靜態方法:

declare_wait_queue_head(name)

動態方法:

wait_queue_head_t my_queue;

init_waitqueue_head(&my_queue);

linux中最簡單的休眠方式是下面的巨集, 

wait_event(queue, condition)  /*程序將被置於非中斷休眠(uninterruptible sleep)*/

wait_event_interruptible(queue, condition) /*程序可被訊號中斷休眠,返回非0值表示休眠被訊號中斷*/

wait_event_timeout(queue, condition, timeout)    /*等待限定時間jiffy,condition滿足其一返回0*/

wait_event_interruptible_timeout(queue, condition, timeout)

queue是等待佇列頭,傳值方式

condition是任意乙個布林表示式,在休眠前後多次對condition求值,為真則喚醒

喚醒程序的基本函式是wake_up

void wake_up(wait_queue_head_t *queue);    /*喚醒等待在給定queue上的所有程序*/

void wake_up_interruptible(wait_queue_head_t *queue);

實踐中,一般是wait_event和wake_up,wait_event_interruptible和wake_up_interruptible成對使用

高階休眠

將程序置於休眠的步驟:

(1)分配和初始化乙個 wait_queue_t 結構, 隨後將其新增到正確的等待佇列

struct __wait_queue ;typedef struct __wait_queue wait_queue_t;(

2)設定程序狀態,標記為休眠。2.6核心中,使用下面的函式:

void set_current_state(int new_state);

在 中定義有幾個任務狀態:task_running 意思是程序能夠執行。有 2 個狀態指示乙個程序是在睡眠: task_interruptible 和 task_untinterruptible

(3)最後一步是放棄處理器。 但必須先檢查進入休眠的條件。如果不做檢查會引入競態: 如果在忙於上面的這個過程時有其他的執行緒剛剛試圖喚醒你,你可能錯過喚醒且長時間休眠。因此典型的**下

if (!condition) 

schedule( );    /*呼叫排程器,並讓出cpu*/

如果**只是從 schedule 返回,則程序處於task_running 狀態。 如果不需睡眠而跳過對 schedule 的呼叫,必須將任務狀態重置為 task_running,還必要從等待佇列中去除這個程序,否則它可能被多次喚醒。

手工休眠

上面的程序休眠步驟可通過手工設定:

(1)建立和初始化乙個等待佇列。常由巨集定義完成:

define_wait(my_wait);

name 是等待佇列入口項的名字. 也可以用2步來做:

wait_queue_t my_wait;

init_wait(&my_wait);

常用的做法是放乙個 define_wait 在迴圈的頂部,來實現休眠

(2)新增等待佇列入口到佇列,並設定程序狀態:

void prepare_to_wait(wait_queue_head_t *queue, 

wait_queue_t *wait, 

int state); 

queue 和 wait 分別地是等待佇列頭和程序入口。state 是程序的新狀態:task_interruptible(可中斷休眠,推薦)或task_uninterruptible(不可中斷休眠,不推薦)

(3)在檢查確認仍然需要休眠之後呼叫 schedule

if (!condition) 

schedule( );    /*呼叫排程器,並讓出cpu*/

認真地看簡單休眠中的 wait_event(queue, condition) 和 wait_event_interruptible(queue, condition) 底層原始碼會發現,其實他們只是手工休眠中的函式的組合。所以怕麻煩的話還是用wait_event比較好。

獨佔等待

當乙個程序呼叫 wake_up 在等待佇列上,所有的在這個佇列上等待的程序被置為可執行的。 這在許多情況下是正確的做法。但有時,可能只有乙個被喚醒的程序將成功獲得需要的資源,而其餘的將再次休眠。這時如果等待佇列中的程序數目大,這可能嚴重降低系統效能。為此,核心開發者增加了乙個「獨佔等待」選項。它與乙個正常的睡眠有 2 個重要的不同:

(1)當等待佇列入口設定了 wq_flag_excluseve 標誌,它被新增到等待佇列的尾部;否則,新增到頭部。

(2)當 wake_up 被在乙個等待佇列上呼叫, 它在喚醒第乙個有 wq_flag_exclusive 標誌的程序後停止喚醒.但核心仍然每次喚醒所有的非獨佔等待。

採用獨佔等待要滿足 2 個條件:

(1)希望對資源進行有效競爭;

(2)當資源可用時,喚醒乙個程序就足夠來完全消耗資源。

使乙個程序進入獨佔等待,可呼叫: 

void prepare_to_wait_exclusive(wait_queue_head_t *queue, wait_queue_t *wait, int state); 

注意:無法使用 wait_event 和它的變體來進行獨佔等待.

喚醒函式

很少會需要呼叫wake_up_interruptible 之外的喚醒函式,但為完整起見,這裡是整個集合:

wake_up(wait_queue_head_t *queue); 

wake_up_interruptible(wait_queue_head_t *queue); 

wake_up 喚醒佇列中的每個非獨佔等待程序和乙個獨佔等待程序。wake_up_interruptible 同樣, 除了它跳過處於不可中斷休眠的程序。它們在返回之前, 使乙個或多個程序被喚醒、被排程(如果它們被從乙個原子上下文呼叫, 這就不會發生).

wake_up_nr(wait_queue_head_t *queue, int nr); 

wake_up_interruptible_nr(wait_queue_head_t *queue, int nr); 

這些函式類似 wake_up, 除了它們能夠喚醒多達 nr 個獨佔等待者, 而不只是乙個. 注意傳遞 0 被解釋為請求所有的互斥等待者都被喚醒

wake_up_all(wait_queue_head_t *queue); 

wake_up_interruptible_all(wait_queue_head_t *queue); 

這種 wake_up 喚醒所有的程序, 不管它們是否進行獨佔等待(可中斷的型別仍然跳過在做不可中斷等待的程序)

wake_up_interruptible_sync(wait_queue_head_t *queue); 

乙個被喚醒的程序可能搶占當前程序, 並且在 wake_up 返回之前被排程到處理器。 但是, 如果你需要不要被排程出處理器時,可以使用 wake_up_interruptible 的"同步"變體. 這個函式最常用在呼叫者首先要完成剩下的少量工作,且不希望被排程出處理器時。

Linux程序休眠和喚醒

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!當程序以阻塞的方式通訊,在得到結果前程序會掛起休眠。為了將程序以一種安全的方式進入休眠,我們需要牢記兩條規則 一 永遠不要在原子上下文中進入休眠。二 程序休眠後,對環境一無所知。喚醒後,必須再次檢查以確保我們等待的條件真正為真 簡單休眠 完成喚醒任...

Linux 休眠喚醒(一)

說明 1.based on linux2.6.32,only for mem sdr 2.有興趣請先參考閱讀 電源管理方案apm和acpi比較.doc linux系統的休眠與喚醒簡介.doc 4.基於手上的乙個專案來討論,這裡只討論共性的地方 雖然linux支援三種省電模式 standby susp...

Linux 休眠喚醒(一)

說明 1.based on linux2.6.32,only for mem sdr 2.有興趣請先參考閱讀 電源管理方案apm和acpi比較.doc linux系統的休眠與喚醒簡介.doc 4.基於手上的乙個專案來討論,這裡只討論共性的地方 雖然linux支援三種省電模式 standby susp...