如何設定linux程序的休眠(等待佇列)

2021-12-29 16:27:33 字數 4145 閱讀 2375

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

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

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

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

簡單休眠

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

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*/

(4)schedule 返回,就到了清理時間:

void finish_wait(wait_queue_head_t *queue, wait_queue_t *wait);

認真地看簡單休眠中的 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 的"同步"變體. 這個函式最常用在呼叫者首先要完成剩下的少量工作,且不希望被排程出處理器時。

作者 fbi888xh

linux程序的休眠(等待佇列)

size medium 當程序以阻塞的方式通訊,在得到結果前程序會掛起休眠。為了將程序以一種安全的方式進入休眠,我們需要牢記兩條規則 一 永遠不要在原子上下文中進入休眠。二 程序休眠後,對環境一無所知。喚醒後,必須再次檢查以確保我們等待的條件真正為真 簡單休眠 完成喚醒任務的 還必須能夠找到我們的程...

Linux程序休眠和喚醒

當程序以阻塞的方式通訊,在得到結果前程序會掛起休眠。為了將程序以一種安全的方式進入休眠,我們需要牢記兩條規則 一 永遠不要在原子上下文中進入休眠。二 程序休眠後,對環境一無所知。喚醒後,必須再次檢查以確保我們等待的條件真正為真 簡單休眠 完成喚醒任務的 還必須能夠找到我們的程序,這樣才能喚醒休眠的程...

Linux程序休眠和喚醒

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