create_workqueue和create_singlethread_workqueue【轉】

本文轉載自:http://bgutech.blog.163.com/blog/static/18261124320116181119889/

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

工作隊列(workqueue)是另外一種將工作推后執行的形式.工作隊列可以把工作推后,交由一個內核線程去執行,也就是說,這個下半部分可以在進程上下文中執行。最重要的就是工作隊列允許被重新調度甚至是睡眠。

2. 數據結構
我們把推后執行的任務叫做工作(work),描述它的數據結構為work_struct,
struct work_struct {
??? atomic_long_t data;?????? /*工作處理函數func的參數*/
#define WORK_STRUCT_PENDING 0??????? /* T if work item pending execution */
#define WORK_STRUCT_STATIC 1??????? /* static initializer (debugobjects) */
#define WORK_STRUCT_FLAG_MASK (3UL)
#define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK)
??? struct list_head entry;??????? /*連接工作的指針*/
??? work_func_t func;????????????? /*工作處理函數*/
#ifdef CONFIG_LOCKDEP
??? struct lockdep_map lockdep_map;
#endif
};


這些工作以隊列結構組織成工作隊列(workqueue),其數據結構為workqueue_struct,
struct workqueue_struct {
?struct cpu_workqueue_struct *cpu_wq;
?struct list_head list;
?const char *name;?? /*workqueue name*/
?int singlethread;?? /*是不是單線程 - 單線程我們首選第一個CPU -0表示采用默認的工作者線程event*/
?int freezeable;??/* Freeze threads during suspend */
?int rt;
};?

如果是多線程,Linux根據當前系統CPU的個數創建cpu_workqueue_struct 其結構體就是,
truct cpu_workqueue_struct {
?spinlock_t lock;/*因為工作者線程需要頻繁的處理連接到其上的工作,所以需要枷鎖保護*/
?struct list_head worklist;
?wait_queue_head_t more_work;
?struct work_struct *current_work; /*當前的work*/
?struct workqueue_struct *wq;???/*所屬的workqueue*/
?struct task_struct *thread; /*任務的上下文*/
} ____cacheline_aligned;
在在該結構主要維護了一個任務隊列,以及內核線程需要睡眠的等待隊列,另外還維護了一個任務上下文,即task_struct。
三者之間的關系如下:

workqueue - G-tech - G-tech的博客

?
3. 創建工作
3.1 創建工作queue
a. create_singlethread_workqueue(name)
該函數的實現機制如下圖所示,函數返回一個類型為struct workqueue_struct的指針變量,該指針變量所指向的內存地址在函數內部調用kzalloc動態生成。所以driver在不再使用該work queue的情況下調用void destroy_workqueue(struct workqueue_struct *wq)來釋放此處的內存地址。

workqueue - G-tech - G-tech的博客

?
圖中的cwq是一per-CPU類型的地址空間。對于create_singlethread_workqueue而言,即使是對于多CPU系統,內核也只負責創建一個worker_thread內核進程。該內核進程被創建之后,會先定義一個圖中的wait節點,然后在一循環體中檢查cwq中的worklist,如果該隊列為空,那么就會把wait節點加入到cwq中的more_work中,然后休眠在該等待隊列中。

Driver調用queue_work(struct workqueue_struct *wq, struct work_struct *work)向wq中加入工作節點。work會依次加在cwq->worklist所指向的鏈表中。queue_work向cwq->worklist中加入一個work節點,同時會調用wake_up來喚醒休眠在cwq->more_work上的worker_thread進程。wake_up會先調用wait節點上的autoremove_wake_function函數,然后將wait節點從cwq->more_work中移走。

worker_thread再次被調度,開始處理cwq->worklist中的所有work節點...當所有work節點處理完畢,worker_thread重新將wait節點加入到cwq->more_work,然后再次休眠在該等待隊列中直到Driver調用queue_work...

b. create_workqueue

workqueue - G-tech - G-tech的博客

?

相對于create_singlethread_workqueue, create_workqueue同樣會分配一個wq的工作隊列,但是不同之處在于,對于多CPU系統而言,對每一個CPU,都會為之創建一個per-CPU的cwq結構,對應每一個cwq,都會生成一個新的worker_thread進程。但是當用queue_work向cwq上提交work節點時,是哪個CPU調用該函數,那么便向該CPU對應的cwq上的worklist上增加work節點。

c.小結
當用戶調用workqueue的初始化接口create_workqueue或者create_singlethread_workqueue對workqueue隊列進行初始化時,內核就開始為用戶分配一個workqueue對象,并且將其鏈到一個全局的workqueue隊列中。然后Linux根據當前CPU的情況,為workqueue對象分配與CPU個數相同的cpu_workqueue_struct對象,每個cpu_workqueue_struct對象都會存在一條任務隊列。緊接著,Linux為每個cpu_workqueue_struct對象分配一個內核thread,即內核daemon去處理每個隊列中的任務。至此,用戶調用初始化接口將workqueue初始化完畢,返回workqueue的指針。Workqueue初始化完畢之后,將任務運行的上下文環境構建起來了,但是具體還沒有可執行的任務,所以,需要定義具體的work_struct對象。然后將work_struct加入到任務隊列中,Linux會喚醒daemon去處理任務。

?上述描述的workqueue內核實現原理可以描述如下:

workqueue - G-tech - G-tech的博客

?

3.2? 創建工作
要使用工作隊列,首先要做的是創建一些需要推后完成的工作。可以通過DECLARE_WORK在編譯時靜態地建該結構:
DECLARE_WORK(name,void (*func) (void *), void *data);
這樣就會靜態地創建一個名為name,待執行函數為func,參數為data的work_struct結構。
同樣,也可以在運行時通過指針創建一個工作:
INIT_WORK(structwork_struct *work, woid(*func) (void *), void *data);

4. 調度
a. schedule_work

在大多數情況下, 并不需要自己建立工作隊列,而是只定義工作, 將工作結構掛接到內核預定義的事件工作隊列中調度, 在kernel/workqueue.c中定義了一個靜態全局量的工作隊列static struct workqueue_struct *keventd_wq;默認的工作者線程叫做events/n,這里n是處理器的編號,每個處理器對應一個線程。比如,單處理器的系統只有events/0這樣一個線程。而雙處理器的系統就會多一個events/1線程。
調度工作結構, 將工作結構添加到全局的事件工作隊列keventd_wq,調用了queue_work通用模塊。對外屏蔽了keventd_wq的接口,用戶無需知道此參數,相當于使用了默認參數。keventd_wq由內核自己維護,創建,銷毀。這樣work馬上就會被調度,一旦其所在的處理器上的工作者線程被喚醒,它就會被執行。

b. schedule_delayed_work(&work,delay);
有時候并不希望工作馬上就被執行,而是希望它經過一段延遲以后再執行。在這種情況下,同時也可以利用timer來進行延時調度,到期后才由默認的定時器回調函數進行工作注冊。延遲delay后,被定時器喚醒,將work添加到工作隊列wq中。

工作隊列是沒有優先級的,基本按照FIFO的方式進行處理。

?

5. 示例:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/workqueue.h>

static struct workqueue_struct *queue=NULL;
static struct work_struct?? work;

staticvoid work_handler(struct work_struct *data)
{
?????? printk(KERN_ALERT"work handler function.\n");
}

static int __init test_init(void)
{
????? queue=create_singlethread_workqueue("hello world");/*創建一個單線程的工作隊列*/
????? if (!queue)
??????????? goto err;

?????? INIT_WORK(&work,work_handler);
?????? schedule_work(&work);

????? return0;
err:
????? return-1;
}

static?? void __exit test_exit(void)
{
?????? destroy_workqueue(queue);
}
MODULE_LICENSE("GPL");
module_init(test_init);
module_exit(test_exit);

轉載于:https://www.cnblogs.com/zzb-Dream-90Time/p/6476018.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/253290.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/253290.shtml
英文地址,請注明出處:http://en.pswp.cn/news/253290.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

平安城市與智慧城市對接的關鍵要素

平安城市經過前兩個階段&#xff08;布點、聯網&#xff09;的大規模建設之后&#xff0c;如今正向系統應用深化&#xff0c;數據深入挖掘利用的方向發展。以視頻監控為基礎單元&#xff0c;一些城市開始嘗試在既有的社會治安管理平臺系統基礎上拓展更多的應用功能&#xff0c;…

vue學習之路.02

2019獨角獸企業重金招聘Python工程師標準>>> 第一個vue項目 1.創建 vue init webpack app01 2.安裝依賴 cd app01 npm install 3.構建 npm run dev 啟動本機的8080端口 或 …

等價表達式

小目標的最后一步。 原題鏈接&#xff1a;https://www.luogu.org/problem/show?pid1054 精力不足&#xff0c;代碼工作可能要放在后幾天。。。 思路已經明確了&#xff0c;我說一下。 這道題的大意是給出若干表達式&#xff0c;問這些表達式的值和初始表達式的值是不是相等。 …

解析電子墨水屏技術(工作原理與LCD的區別)

閱讀電子書早已成為大家生活中一部分&#xff0c;方便輕巧的電子版書籍更便于攜帶&#xff0c;而電子閱讀器也不僅僅局限于電腦、手機等傳統設備&#xff0c;新興的電子書閱讀器漸漸為我們所接受。E-ink電子墨水技術就是現在最著名的產品之一&#xff0c;他的出現讓電子書閱讀器…

27:級數求和

27:級數求和 查看提交統計提問總時間限制: 1000ms內存限制: 65536kB描述已知&#xff1a;Sn 1&#xff0b;1&#xff0f;2&#xff0b;1&#xff0f;3&#xff0b;…&#xff0b;1&#xff0f;n。顯然對于任意一個整數K&#xff0c;當n足夠大的時候&#xff0c;Sn大于K。 現給出…

入門視頻采集與處理(BT656簡介) 轉

凡是做模擬信號采集的&#xff0c;很少不涉及BT.656標準的&#xff0c;因為常見的模擬視頻信號采集芯片都支持輸出BT.656的數字信號&#xff0c;那么&#xff0c;BT.656到底是何種格式呢&#xff1f;本文將主要介紹 標準的 8bit BT656&#xff08;4:2:2&#xff09;YCbCr SDTV&…

眼圖(Eye Diagram)與數字信號測試

問題: 什么是眼圖&#xff1f;它用在什么場合&#xff1f;反映了波形的什么信息&#xff1f;NI相應的解決方案是怎樣的&#xff1f; 解答: 眼圖&#xff08;Eye Diagram&#xff09;可以顯示出數字信號的傳輸質量&#xff0c;經常用于需要對電子設備、芯片中串行數字信號或者…

BZOJ 1609 [Usaco2008 Feb]Eating Together麻煩的聚餐:LIS LDS (nlogn)

題目鏈接&#xff1a;http://www.lydsy.com/JudgeOnline/problem.php?id1609 題意&#xff1a; 給你一個只由數字"1,2,3"組成的序列a[i]&#xff0c;共n個數。 你可以任意更改這些數字&#xff0c;使得序列中每一種數字都“站在一起”&#xff0c;并且單調不減或不增…

Oracle 數據庫字典 sys.obj$ 表中關于type#的解釋

sys.obj$ 表是oracle 數據庫字典表中的對象基礎表&#xff0c;所有對象都在該表中有記錄&#xff0c;其中type#字段表明對象類型&#xff0c;比如有一個表 test &#xff0c;則該對象在sys.obj$ 中存在一條記錄&#xff0c;name列為test&#xff0c; type#列為2&#xff0c;表示…

Python高級特性:列表生成式

列表生成式即List Comprehensions&#xff0c;是Python內置的非常簡單卻強大的可以用來創建list的生成式。 最常見的例子&#xff1a; 生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]可以用list(range(1, 11))&#xff1a;>>> list(range(1, 11)) [1, 2, 3, 4, 5, 6, 7, 8…

2018年智能音箱對比

眾所周知&#xff0c;2014年底&#xff0c;電商巨頭亞馬遜推出智能音箱產品Echo之后&#xff0c;引起市場的強烈反響。隨后、谷歌、微軟、蘋果均開始布局智能音箱市場&#xff0c;國內公司以玲瓏科技打頭陣。2017年國內公司紛紛發布智能音箱&#xff0c;被稱為智能音箱元年。經…

AMD與CMD區別

AMD&#xff1a;異步模塊定義&#xff0c;是一個瀏覽器端模塊化開發的規范&#xff0c;由于不是原生JS支持,使用AMD規范需要用到require.js庫require.js注意解決兩個問題1、多個js文件可能有依賴關系&#xff0c;被依賴的文件需要早于依賴它的文件加載到瀏覽器2、js加載的時候瀏…

[LeetCode] Interleaving String

1. 是一個很明顯的動態規劃題。 2. s3中的每個字符不是s1中的就是s2中的&#xff0c;只要根據它之前的狀態做轉移就可以。 1 class Solution {2 public:3 bool isInterleave(string s1, string s2, string s3) {4 int n s1.size();5 int m s2.size();6 …

Python Urllib庫詳解

Urllib庫詳解 什么是Urllib? Python內置的HTTP請求庫 urllib.request 請求模塊 urllib.error 異常處理模塊 urllib.parse url解析模塊 urllib.robotparser robots.txt解析模塊 相比Python2變化 python2 import urllib2 response urllib2.urlopen(http://www.baidu.com) pytho…

LVDS通信接口詳細介紹

1. 概述 LVDS Low-Voltage Differential Signaling 低電壓差分信號&#xff0c;屬于平衡傳輸信號。 這種技術的核心是采用極低的電壓擺幅高速差動傳輸數據&#xff0c;從而有以下特點&#xff1a; 低功耗---低誤碼率---低串擾---低抖動---低輻射 良好的信號完整性。 推…

ThinkPHP簡單的驗證碼實現

ThinkPHP簡單的驗證碼實現 寫一個最簡單的TP驗證碼。 寫Controller 首先在Controller/IndexController.class.php&#xff08;簡稱Index&#xff09;文件中編輯&#xff1a; 1 <?php 2 namespace Home\Controller; 3 use Think\Controller; 4 use Think\Verify;//這個類…

Celery框架簡單實例

Python 中可以使用Celery框架 Celery框架是提供異步任務處理的框架&#xff0c;有兩種用法&#xff0c;一種&#xff1a;應用程式發布任務消息&#xff0c;后臺Worker監聽執行&#xff0c;好處在于不影響應用程序繼續執行。第二種&#xff0c;設置定時執行&#xff08;這邊沒測…

沸騰新十年 | 中國語音產業江湖和科大訊飛的前半生

沸騰新十年 | 中國語音產業江湖和科大訊飛的前半生 2019-01-09 來源:左林右貍 寫在前面&#xff1a; 這是《沸騰新十年》的第十一篇劇透文&#xff0c;也是2019年的第一篇劇透文&#xff0c;從確認選題到采編到反復修改&#xff0c;這篇稿子操作時間前后歷經近半年。究其原…