<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一文讀懂 | Linux延時(shí)隊(duì)列工作原理

          共 3068字,需瀏覽 7分鐘

           ·

          2021-10-22 01:53

          當(dāng)進(jìn)程要獲取某些資源(例如從網(wǎng)卡讀取數(shù)據(jù))的時(shí)候,但資源并沒(méi)有準(zhǔn)備好(例如網(wǎng)卡還沒(méi)接收到數(shù)據(jù)),這時(shí)候內(nèi)核必須切換到其他進(jìn)程運(yùn)行,直到資源準(zhǔn)備好再喚醒進(jìn)程。

          waitqueue (等待隊(duì)列)?就是內(nèi)核用于管理等待資源的進(jìn)程,當(dāng)某個(gè)進(jìn)程獲取的資源沒(méi)有準(zhǔn)備好的時(shí)候,可以通過(guò)調(diào)用?add_wait_queue()?函數(shù)把進(jìn)程添加到?waitqueue?中,然后切換到其他進(jìn)程繼續(xù)執(zhí)行。當(dāng)資源準(zhǔn)備好,由資源提供方通過(guò)調(diào)用?wake_up()?函數(shù)來(lái)喚醒等待的進(jìn)程。

          等待隊(duì)列初始化

          要使用?waitqueue?首先需要聲明一個(gè)?wait_queue_head_t?結(jié)構(gòu)的變量,wait_queue_head_t?結(jié)構(gòu)定義如下:

          struct?__wait_queue_head?{
          ????spinlock_t?lock;
          ????struct?list_head?task_list;
          };

          waitqueue?本質(zhì)上是一個(gè)鏈表,而?wait_queue_head_t?結(jié)構(gòu)是?waitqueue?的頭部,lock?字段用于保護(hù)等待隊(duì)列在多核環(huán)境下數(shù)據(jù)被破壞,而?task_list?字段用于保存等待資源的進(jìn)程列表。

          可以通過(guò)調(diào)用?init_waitqueue_head()?函數(shù)來(lái)初始化?wait_queue_head_t?結(jié)構(gòu),其實(shí)現(xiàn)如下:

          void?init_waitqueue_head(wait_queue_head_t?*q)
          {
          ????spin_lock_init(&q->lock);
          ????INIT_LIST_HEAD(&q->task_list);
          }

          初始化過(guò)程很簡(jiǎn)單,首先調(diào)用?spin_lock_init()?來(lái)初始化自旋鎖?lock,然后調(diào)用?INIT_LIST_HEAD()?來(lái)初始化進(jìn)程鏈表。

          向等待隊(duì)列添加等待進(jìn)程

          要向?waitqueue?添加等待進(jìn)程,首先要聲明一個(gè)?wait_queue_t?結(jié)構(gòu)的變量,wait_queue_t?結(jié)構(gòu)定義如下:

          typedef?int?(*wait_queue_func_t)(wait_queue_t?*wait,?unsigned?mode,?int?sync,?void?*key);

          struct?__wait_queue?{
          ????unsigned?int?flags;
          ????void?*private;
          ????wait_queue_func_t?func;
          ????struct?list_head?task_list;
          };

          下面說(shuō)明一下各個(gè)成員的作用:

          1. flags: 可以設(shè)置為?WQ_FLAG_EXCLUSIVE,表示等待的進(jìn)程應(yīng)該獨(dú)占資源(解決驚群現(xiàn)象)。
          2. private: 一般用于保存等待進(jìn)程的進(jìn)程描述符?task_struct
          3. func: 喚醒函數(shù),一般設(shè)置為?default_wake_function()?函數(shù),當(dāng)然也可以設(shè)置為自定義的喚醒函數(shù)。
          4. task_list: 用于連接其他等待資源的進(jìn)程。

          可以通過(guò)調(diào)用?init_waitqueue_entry()?函數(shù)來(lái)初始化?wait_queue_t?結(jié)構(gòu)變量,其實(shí)現(xiàn)如下:

          static?inline?void?init_waitqueue_entry(wait_queue_t?*q,?struct?task_struct?*p)
          {
          ????q->flags?=?0;
          ????q->private?=?p;
          ????q->func?=?default_wake_function;
          }

          也可以通過(guò)調(diào)用?init_waitqueue_func_entry()?函數(shù)來(lái)初始化為自定義的喚醒函數(shù):

          static?inline?void?init_waitqueue_func_entry(wait_queue_t?*q,?wait_queue_func_t?func)
          {
          ????q->flags?=?0;
          ????q->private?=?NULL;
          ????q->func?=?func;
          }

          初始化完?wait_queue_t?結(jié)構(gòu)變量后,可以通過(guò)調(diào)用?add_wait_queue()?函數(shù)把等待進(jìn)程添加到等待隊(duì)列,其實(shí)現(xiàn)如下:

          void?add_wait_queue(wait_queue_head_t?*q,?wait_queue_t?*wait)
          {
          ????unsigned?long?flags;

          ????wait->flags?&=?~WQ_FLAG_EXCLUSIVE;
          ????spin_lock_irqsave(&q->lock,?flags);
          ????__add_wait_queue(q,?wait);
          ????spin_unlock_irqrestore(&q->lock,?flags);
          }

          static?inline?void?__add_wait_queue(wait_queue_head_t?*head,?wait_queue_t?*new)
          {
          ????list_add(&new->task_list,?&head->task_list);
          }

          add_wait_queue()?函數(shù)的實(shí)現(xiàn)很簡(jiǎn)單,首先通過(guò)調(diào)用?spin_lock_irqsave()?上鎖,然后調(diào)用?list_add()?函數(shù)把節(jié)點(diǎn)添加到等待隊(duì)列即可。

          wait_queue_head_t?結(jié)構(gòu)與?wait_queue_t?結(jié)構(gòu)之間的關(guān)系如下圖:

          waitqueue

          休眠等待進(jìn)程

          當(dāng)把進(jìn)程添加到等待隊(duì)列后,就可以休眠當(dāng)前進(jìn)程,讓出CPU給其他進(jìn)程運(yùn)行,要休眠進(jìn)程可以通過(guò)一下方式:

          set_current_state(TASK_INTERRUPTIBLE);
          schedule();

          代碼?set_current_state(TASK_INTERRUPTIBLE)?可以把當(dāng)前進(jìn)程運(yùn)行狀態(tài)設(shè)置為?可中斷休眠?狀態(tài),調(diào)用?schedule()?函數(shù)可以使當(dāng)前進(jìn)程讓出CPU,切換到其他進(jìn)程執(zhí)行。

          喚醒等待隊(duì)列

          當(dāng)資源準(zhǔn)備好后,就可以喚醒等待隊(duì)列中的進(jìn)程,可以通過(guò)?wake_up()?函數(shù)來(lái)喚醒等待隊(duì)列中的進(jìn)程。wake_up()?最終會(huì)調(diào)用?__wake_up_common(),其實(shí)現(xiàn)如下:

          static?void?__wake_up_common(wait_queue_head_t?*q,?
          ????unsigned?int?mode,?int?nr_exclusive,?int?sync,?void?*key)
          {
          ????wait_queue_t?*curr,?*next;

          ????list_for_each_entry_safe(curr,?next,?&q->task_list,?task_list)?{
          ????????unsigned?flags?=?curr->flags;

          ????????if?(curr->func(curr,?mode,?sync,?key)?&&
          ????????????????(flags?&?WQ_FLAG_EXCLUSIVE)?&&?!--nr_exclusive)
          ????????????break;
          ????}
          }

          可以看出,喚醒等待隊(duì)列就是變量等待隊(duì)列的等待進(jìn)程,然后調(diào)用喚醒函數(shù)來(lái)喚醒它們。


          瀏覽 31
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  99九九国产毛片 | 18禁91 | 免费看日皮视频 | 特级艺体西西444WWw | www.夜夜撸 |