91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Linux系統中workqueue機制如何理解

發布時間:2022-01-26 17:55:50 來源:億速云 閱讀:188 作者:柒染 欄目:開發技術

本篇文章給大家分享的是有關Linux系統中workqueue機制如何理解,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

workqueue簡介:

Linux中的Workqueue機制就是為了簡化內核線程的創建。通過調用workqueue的接口就能創建內核線程。并且可以根據當前系統CPU的個數創建線程的數量,使得線程處理的事務能夠并行化。workqueue是內核中實現簡單而有效的機制,他顯然簡化了內核daemon的創建,方便了用戶的編程,

Linux中的workqueue機制

Linux中的workqueue機制是中斷底半部的一種實現,同時也是一種通用的任務異步處理的手段。進入workqueue隊列處理的任務(work item)在代碼中由”work_struct “結構體表示(定義在include/linux/workqueue.h):

 struct work_struct {  struct list_head entry;  work_func_t func;  atomic_long_t data; };

其中,”entry”表示其所掛載的workqueue隊列的節點,”func”就是要執行的任務的入口函數。而”data”表示的意義就比較豐富了。最后的4個bits是作為”flags”標志位使用的,中間的4個bits是用于flush功能的”color”。flush功能簡單地說就是:等待workqueue隊列上的任務都處理完,并清空workqueue隊列(由于筆者也沒有深入研究過這一塊的具體實現原理,在本文的敘述中就不涉及這一部分內容了)。

剩下的bits在不同的場景下有不同的含義(相當于C語言里的”union”),它可以指向work item所在的workqueue隊列的地址,由于低8位被挪作他用,因此要求workqueue隊列的地址是按照256字節對齊的。它還可以表示處理work item的worker線程所在的pool的ID(關于pool將在本文的后半部分介紹)。

這種在一個C語言變量里塞入不同的類型的數據的方法在Linux的代碼實現中還是不難見到的,在目前的workqueue機制中,”flags”和”color”所需的bits都較少,單獨使用整形變量去表示確實會增加一定的內存消耗。但這種犧牲可讀性的做法也被一些內核開發者認為是比較”ugly”的。

Linux系統中workqueue機制如何理解

為了充分利用locality,通常選擇將處理hardirq的CPU作為該hardirq對應的workqueue底半部的執行CPU,在早期Linux的實現中,每個CPU對應一個workqueue隊列,并且每個CPU上只有一個worker線程來處理這個workqueue隊列,也就是說workqueue隊列和worker線程都是per-CPU的,且一一對應。

Linux系統中workqueue機制如何理解

讓我們看看這種設計存在什么問題。假設現在一個work item(設為w0)被添加到了workqueue隊列上。w0需要運行5ms后休眠10ms,接著再運行5ms。在w0開始運行5ms和10ms后,另外兩個work items(設為w1和w2)也分別加入了workqueue隊列,w1和w2都是需要運行5ms,然后再休眠10ms(該示例來自內核Documentation/core-api/workqueue.rst文檔)。

因為只有1個worker線程,所以即便在執行某個work item的時候休眠,其他的work item也得不到執行,因此將這3個work item執行完畢將總共需要55ms的時間。

Linux系統中workqueue機制如何理解

假設現在一個CPU上有2個worker線程,分別為worker 1和worker 2,那么整個執行時間將縮短到35ms:

Linux系統中workqueue機制如何理解

如果一個CPU上有3個worker線程,執行時間將進一步縮短到25ms:

Linux系統中workqueue機制如何理解

cmwq

這種在一個CPU上運行多個worker線程的做法,就是2.6.36版本引入的,也是現在Linux內核所采用的concurrency managed workqueue,簡稱cmwq。一個CPU上是不可能“同時”運行多個線程的,所以這里的名稱是concurrency(并發),而不是parallelism(并行)。

顯然,設置合適的worker線程數目是很關鍵的,多了浪費資源,少了又不能充分利用CPU。大體的原則就是:如果現在一個CPU上的所有worker線程都進入了睡眠狀態,但workqueue隊列上還有未處理的work item,那么就再啟動一個worker線程。

一個CPU上的所有worker線程共同構成了一個worker pool(此概念由內核v3.8引入),我們可能比較熟悉memory pool,當需要內存時,就從空余的memory pool中去獲取,同樣地,當workqueue上有work item待處理時,我們就從worker pool里挑選一個空閑的worker線程來服務這個work item。

worker pool在代碼中由”worker_pool “結構體表示(定義在kernel/workqueue.c):

 struct worker_pool {  spinlock_t  lock;  /* the pool lock */  int   cpu;  /* the associated cpu */  int   id;  /* pool ID */ 
  struct list_head idle_list; /* list of idle workers */  DECLARE_HASHTABLE(busy_hash, 6);        /* hash of busy workers */     ... }

如果一個worker正在處理work item,那么它就是busy的狀態,將掛載在busy workers組成的6階的hash表上。既然是hash表,那么就需要key,充當這個key的是正在被處理的work item的內存地址。

如果一個worker沒有處理work item,那么它就是idle的狀態,將掛載在idle workers組成的鏈表上。因為空閑的worker線程數目較少,用鏈表管理就可以了,而busy的worker線程可能較多,所以用hash表來組織,以加快查找的速度。

前面說過,有未處理的work item,內核就會啟動一個新的worker線程,以提高效率。有創建就有消亡,當現在空閑的worker線程過多的時候,就需要銷毀一部分worker線程,以節省CPU資源。就像一家公司,在項目緊張,人員不足的時候需要招人,在項目不足,人員過剩的時候可能就會裁員。至于保留多少空閑線程可以取得較理想的平衡,則涉及到一個頗為復雜的算法,在此就不展開了。

Linux系統中workqueue機制如何理解

worker線程在代碼中由”worker “結構體表示(定義在kernel/workqueue_internal.h):

 struct worker {  struct worker_pool  *pool;  /* the associated pool */  union {   struct list_head  entry; /* while idle */   struct hlist_node hentry; /* while busy */  }; 
  struct work_struct *current_work;   /* work being processed */  work_func_t   current_func;   /* current_work's fn */  struct task_struct *task;    /* worker task */ 
  struct pool_workqueue *current_pwq;     /* current_work's pwq */         ... }

其中,”pool”是這個worker線程所在的worker pool,根據worker線程所處的狀態,它要么在idle worker組成的空閑鏈表中,要么在busy worker組成的hash表中。

“current_work”和”current_func”分別是worker線程正在處理的work item和其對應的入口函數。既然worker線程是一個內核線程,那么不管它是idle,還是busy的,都會對應一個task_struct(由”task”表示)。

Linux系統中workqueue機制如何理解

“current_pwq”指向被服務的work item所在的workqueue隊列,

以上就是Linux系統中workqueue機制如何理解,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

兰考县| 云安县| 广宁县| 永兴县| 会宁县| 湾仔区| 潞西市| 江山市| 子长县| 弋阳县| 房山区| 兴仁县| 邯郸市| 章丘市| 玉溪市| 陵水| 漠河县| 华容县| 璧山县| 民和| 常山县| 封开县| 剑川县| 平南县| 永修县| 西峡县| 九江市| 江山市| 左权县| 连云港市| 锡林郭勒盟| 勃利县| 阿克陶县| 巴中市| 方城县| 长子县| 陆良县| 辽中县| 樟树市| 越西县| 北川|