自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

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

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

[[429954]]

本文轉(zhuǎn)載自微信公眾號(hào)「Linux內(nèi)核那些事」,作者songsong001 。轉(zhuǎn)載本文請(qǐng)聯(lián)系Linux內(nèi)核那些事公眾號(hào)。

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

waitqueue (等待隊(duì)列) 就是內(nèi)核用于管理等待資源的進(jìn)程,當(dāng)某個(gè)進(jìn)程獲取的資源沒有準(zhǔn)備好的時(shí)候,可以通過調(diào)用 add_wait_queue() 函數(shù)把進(jìn)程添加到 waitqueue 中,然后切換到其他進(jìn)程繼續(xù)執(zhí)行。當(dāng)資源準(zhǔn)備好,由資源提供方通過調(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)定義如下:

  1. struct __wait_queue_head { 
  2.     spinlock_t lock; 
  3.     struct list_head task_list; 
  4. }; 

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

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

  1. void init_waitqueue_head(wait_queue_head_t *q) 
  2.     spin_lock_init(&q->lock); 
  3.     INIT_LIST_HEAD(&q->task_list); 

初始化過程很簡(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)定義如下:

  1. typedef int (*wait_queue_func_t)(wait_queue_t *wait, unsigned mode, int sync, void *key); 
  2.  
  3. struct __wait_queue { 
  4.     unsigned int flags; 
  5.     void *private; 
  6.     wait_queue_func_t func; 
  7.     struct list_head task_list; 
  8. }; 

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

flags: 可以設(shè)置為 WQ_FLAG_EXCLUSIVE,表示等待的進(jìn)程應(yīng)該獨(dú)占資源(解決驚群現(xiàn)象)。

private: 一般用于保存等待進(jìn)程的進(jìn)程描述符 task_struct。

func: 喚醒函數(shù),一般設(shè)置為 default_wake_function() 函數(shù),當(dāng)然也可以設(shè)置為自定義的喚醒函數(shù)。

task_list: 用于連接其他等待資源的進(jìn)程。

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

  1. static inline void init_waitqueue_entry(wait_queue_t *q, struct task_struct *p) 
  2.     q->flags = 0; 
  3.     q->private = p; 
  4.     q->func = default_wake_function; 

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

  1. static inline void init_waitqueue_func_entry(wait_queue_t *q, wait_queue_func_t func) 
  2.     q->flags = 0; 
  3.     q->private = NULL
  4.     q->func = func; 

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

  1. void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait) 
  2.     unsigned long flags; 
  3.  
  4.     wait->flags &= ~WQ_FLAG_EXCLUSIVE; 
  5.     spin_lock_irqsave(&q->lock, flags); 
  6.     __add_wait_queue(q, wait); 
  7.     spin_unlock_irqrestore(&q->lock, flags); 
  8.  
  9. static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new) 
  10.     list_add(&new->task_list, &head->task_list); 

add_wait_queue() 函數(shù)的實(shí)現(xiàn)很簡(jiǎn)單,首先通過調(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)程可以通過一下方式:

  1. set_current_state(TASK_INTERRUPTIBLE); 
  2. 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)程,可以通過 wake_up() 函數(shù)來(lái)喚醒等待隊(duì)列中的進(jìn)程。wake_up() 最終會(huì)調(diào)用 __wake_up_common(),其實(shí)現(xiàn)如下:

  1. static void __wake_up_common(wait_queue_head_t *q,  
  2.     unsigned int mode, int nr_exclusive, int sync, void *key
  3.     wait_queue_t *curr, *next
  4.  
  5.     list_for_each_entry_safe(curr, next, &q->task_list, task_list) { 
  6.         unsigned flags = curr->flags; 
  7.  
  8.         if (curr->func(curr, mode, sync, key) && 
  9.                 (flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive) 
  10.             break; 
  11.     } 

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

 

責(zé)任編輯:武曉燕 來(lái)源: Linux內(nèi)核那些事
相關(guān)推薦

2022-05-12 10:53:42

keepalivevrrp協(xié)議

2019-08-23 12:12:49

MQ消息隊(duì)列

2021-12-16 14:45:09

https架構(gòu)服務(wù)端

2020-10-22 09:35:11

線程池核心線程阻塞隊(duì)列

2017-08-21 10:00:23

遺傳算法Python生物學(xué)

2023-01-09 08:14:08

GoHttpServer

2021-11-02 10:53:56

Linux機(jī)制CPU

2021-10-15 14:28:30

React 組件渲染

2023-12-22 19:59:15

2021-08-04 16:06:45

DataOps智領(lǐng)云

2024-10-12 09:26:32

線程池系統(tǒng)核心線程

2021-02-26 05:24:35

Java垃圾回收

2021-04-30 19:53:53

HugePages大內(nèi)存頁(yè)物理

2024-04-10 10:34:34

Cache系統(tǒng)GPU

2018-09-28 14:06:25

前端緩存后端

2022-09-22 09:00:46

CSS單位

2025-04-03 10:56:47

2022-11-06 21:14:02

數(shù)據(jù)驅(qū)動(dòng)架構(gòu)數(shù)據(jù)

2021-08-11 10:10:26

Linux定時(shí)器數(shù)組

2023-12-18 10:45:31

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)