linux平台下 延迟工作队列实例
? ? ? ? 工作隊列(work queue)是Linux內核中將操作延期執行的一種機制。因為它們是通過守護進程在用戶上下文執行,函數可以睡眠的時間,與內核是無關的。在內核版本2.5開發期間,設計了工作隊列,用以替換此前的keventd機制。
? ? ? ??這種機制和BH或Tasklets不同之處在于工作隊列是把延期的工作交由一個內核線程去執行,因此工作隊列的優勢就在于它允許重新調度甚至睡眠。
? ? ? ??每個工作隊列多有一個數組,數據元素的數目與內核處理器core的數目相同,每個數據元素都列出來將要延期執行的任務。
? ? ? ??對于每個工作隊列來說,內核都會創建一個新的內核守護線程,延期任務使用上下文描述的等待隊列機制,在守護進程的上下午執行。
先定義幾個內核中使用工作隊列時用到的術語方便后面描述。
- workqueues:所有工作項被 ( 需要被執行的工作 ) 排列于該隊列,因此稱作工作隊列 (workqueues) 。
- worker thread:工作者線程 (worker thread) 是一個用于執行工作隊列中各個工作項的內核線程,當工作隊列中沒有工作項時,該線程將變為 idle 狀態。
- single threaded(ST)::工作者線程的表現形式之一,在系統范圍內,只有一個工作者線程為工作隊列服務
- multi threaded(MT):工作者線程的表現形式之一,在多 CPU 系統上每個 CPU 上都有一個工作者線程為工作隊列服務
如何使用工作隊列哪?按如下步驟:
一.?????? 聲明一個工作隊列
staticstruct workqueue_struct *test_wq;
二.?????? 聲明一個延期工作描述實例
static struct delayed_work test_dwq;
三.?????? 聲明并實現一個工作隊列延遲處理函數
voiddelay_func(struct work_struct *work);
voiddelay_func(struct work_struct *work)
{
??? printk(KERN_INFO "My name isdelay_func!\n");
}
四.?????? 初始化一個工作隊列
test_wq = create_workqueue("test_wq");
五.?????? 任務初始化
INIT_DELAYED_WORK(&test_dwq,delay_func);
六. ? ? ? 向工作隊列提交工作項
queue_delayed_work(test_wq, &test_dwq, delay);
七. ? ? ? 取消工作隊列中的工作項
int cancel_delayed_work(test_wq);
? ? ? ?如果這個工作項在它開始執行前被取消,返回值是非零。內核保證給定工作項的執行不會在調用 cancel_delay_work 成功后被執行。 如果 cancel_delay_work 返回 0,則這個工作項可能已經運行在一個不同的處理器,并且仍然可能在調用 cancel_delayed_work 之后被執行。要絕對確保工作函數沒有在 cancel_delayed_work 返回 0 后在任何地方運行,你必須跟隨這個調用之后接著調用 flush_workqueue。在 flush_workqueue 返回后。任何在改調用之前提交的工作函數都不會在系統任何地方運行。
八.?????? 刷新工作隊列
flush_workqueue(test_wq);
九.?????? 工作隊列銷毀
destroy_workqueue(test_wq);
?
涉及到的主要函數與結構體
一.?????? 函數queue_delayed_work()
函數queue_delayed_work()是用于向工作隊列提交delayed_work實例,確保在延期執行之前,至少會經過由delay指定的一段時間(以jiffies為單位)。
該函數首先創建一個由內核定時器,該定時器將在delayed jiffies之內超時。
二.?????? 延期工作描述實例
structdelayed_work {
?????? struct work_struct work; /* 將作為實例被queue_work或queue_work_delayed添加到一個工作隊列*/
?????? struct timer_list timer; /* 延遲時間*/
};
三.?????? alloc_workqueue函數
struct workqueue_struct *alloc_workqueue(char *name, unsigned intflags, int max_active);
name:為工作隊列的名字,而不像 2.6.36 之前實際是為工作隊列服務的內核線程的名字。
Flag: 指明工作隊列的屬性,可以設定的標記如下:
- WQ_NON_REENTRANT:默認情況下,工作隊列只是確保在同一 CPU 上不可重入,即工作項不能在同一 CPU 上被多個工作者線程并發執行,但容許在多個 CPU 上并發執行。但該標志標明在多個 CPU 上也是不可重入的,工作項將在一個不可重入工作隊列中排隊,并確保至多在一個系統范圍內的工作者線程被執行。
- WQ_UNBOUND:工作項被放入一個由特定 gcwq 服務的未限定工作隊列,該客戶工作者線程沒有被限定到特定的 CPU,這樣,未限定工作者隊列就像簡單的執行上下文一般,沒有并發管理。未限定的 gcwq 試圖盡可能快的執行工作項。
- WQ_FREEZEABLE:可凍結 wq 參與系統的暫停操作。該工作隊列的工作項將被暫停,除非被喚醒,否者沒有新的工作項被執行。
- WQ_MEM_RECLAIM:所有的工作隊列可能在內存回收路徑上被使用。使用該標志則保證至少有一個執行上下文而不管在任何內存壓力之下。
- WQ_HIGHPRI:高優先級的工作項將被排練在隊列頭上,并且執行時不考慮并發級別;換句話說,只要資源可用,高優先級的工作項將盡可能快的執行。高優先工作項之間依據提交的順序被執行。
·?????????WQ_CPU_INTENSIVE:CPU 密集的工作項對并發級別并無貢獻,換句話說,可運行的 CPU密集型工作項將不阻止其它工作項。這對于限定得工作項非常有用,因為它期望更多的 CPU 時鐘周期,所以將它們的執行調度交給系統調度器。
·?????????WQ_DRAINING:internal: workqueue is draining
·?????????WQ_RESCUER :internal: workqueue has rescuer
·?????????WQ_MAX_ACTIVE: I like 512, better ideas?
·?????????WQ_MAX_UNBOUND_PER_CPU: 4 * #cpus for unbound wq
·?????????WQ_DFL_ACTIVE:等于WQ_MAX_ACTIVE / 2,
max_active:決定了一個 wq 在 per-CPU 上能執行的最大工作項。比如 max_active 設置為 16 表示一個工作隊列上最多 16 個工作項能同時在 per-CPU 上同時執行。當前實行中,對所有限定工作隊列,max_active 的最大值是 512,而設定為 0 時表示是 256;而對于未限定工作隊列,該最大值為:MAX[512,4 * num_possible_cpus() ],除非有特別的理由需要限流或者其它原因,一般設定為 0 就可以了
實例
/*********************************************** Author: lewiyon@hotmail.com* File name: delay_wq.c* Description: learn delay workqueue* Date: 2011-12-21*********************************************/#include <linux/kernel.h> #include <linux/module.h> #include <linux/proc_fs.h> #include <linux/workqueue.h> #include <linux/sched.h> #include <linux/init.h> #include <linux/interrupt.h>static struct workqueue_struct *test_wq; static struct delayed_work test_dwq;void delay_func(struct work_struct *work);void delay_func(struct work_struct *work) {printk(KERN_INFO "My name is delay_func!\n"); }static int __init example_init(void) {test_wq = create_workqueue("test_wq");if (!test_wq) {printk(KERN_ERR "No memory for workqueue\n");return 1; }printk(KERN_INFO "Create Workqueue successful!\n");INIT_DELAYED_WORK(&test_dwq, delay_func);queue_delayed_work(test_wq, &test_dwq, 0);return 0; }static void __exit example_exit(void) {destroy_workqueue(test_wq);printk(KERN_INFO "Goodbay!\n"); }module_init(example_init); module_exit(example_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("lewiyon <lewiyon@hotmail.com>");轉載于:https://www.cnblogs.com/youngerchina/archive/2011/12/23/5624642.html
總結
以上是生活随笔為你收集整理的linux平台下 延迟工作队列实例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Entity Framework中IQu
- 下一篇: 20个将 JavaScript 用到极致