用例程解釋create_singlethread_workqueue與create_workqueue的區別
系統版本:linux3.4
使用create_singlethread_workqueue創建工作隊列即使對於多CPU系統,內核也只負責在一個cpu上創建一個worker_thread內核線程;而使用create_workqueue創建工作隊列對於多CPU系統,內核將會在每個CPU上創建一個worker_thread內核線程,使得線程處理的事務能夠並行化.
用代碼解釋前先說明一個知識點:
printk任何時候,任何地方都能調用它,可以在中斷上下文和進程上下文中被調用,可以在任何持有鎖時被調用;可以在多處理器上同時被調用,而且調用者連鎖都不必使用
==========================================================================================
例程1:使用create_workqueue創建工作隊列
#include <linux/module.h> #include <linux/init.h> #include <linux/string.h> #include <linux/list.h> #include <linux/sysfs.h> #include <linux/ctype.h> #include <linux/workqueue.h> #include <linux/delay.h> //工作以隊列結構組織成工作隊列(workqueue),其數據結構為workqueue_struct, static struct workqueue_struct *test_wq = NULL; //把推后執行的任務叫做工作(work),描述它的數據結構為work_struct static struct work_struct work; /* *定義工作隊列調用函數 */ void work_func(struct work_struct *work){ while(1){ printk(KERN_ERR "-----%s-----\n",__func__); //printk可以在多處理器上同時被調用 } } static int __init test_init(void){ /*創建工作隊列workqueue_struct,該函數會為cpu創建內核線程*/ test_wq = create_workqueue("test_wq"); /*初始化工作work_struct,指定工作函數*/ INIT_WORK(&work,work_func); /*將工作加入到工作隊列中,最終喚醒內核線程*/ queue_work(test_wq, &work); while(1){ mdelay(1000); printk(KERN_ERR "-----%s-----\n",__func__); } return 0; } static void __exit test_exit(void){ } module_init(test_init); module_exit(test_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("liujin725@outlook.com");
運行結果:沒有打印任何信息,系統直接卡死,卡死原因是因為所有的cpu都被printk占用,系統無法調用其他的進程
=============================================================================
例程2:使用create_singlethread_workqueue創建工作隊列
#include <linux/module.h> #include <linux/init.h> #include <linux/string.h> #include <linux/list.h> #include <linux/sysfs.h> #include <linux/ctype.h> #include <linux/workqueue.h> #include <linux/delay.h> //工作以隊列結構組織成工作隊列(workqueue),其數據結構為workqueue_struct, static struct workqueue_struct *test_wq = NULL; //把推后執行的任務叫做工作(work),描述它的數據結構為work_struct static struct work_struct work; /* *定義工作隊列調用函數 */ void work_func(struct work_struct *work){ while(1){ printk(KERN_ERR "-----%s-----\n",__func__); //printk可以在多處理器上同時被調用 } } static int __init test_init(void){ /*創建工作隊列workqueue_struct,該函數會為cpu創建內核線程*/ test_wq = create_singlethread_workqueue("test_wq"); /*初始化工作work_struct,指定工作函數*/ INIT_WORK(&work,work_func); /*將工作加入到工作隊列中,最終喚醒內核線程*/ queue_work(test_wq, &work); while(1){ mdelay(1000); printk(KERN_ERR "-----%s-----\n",__func__); } return 0; } static void __exit test_exit(void){ } module_init(test_init); module_exit(test_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("liujin725@outlook.com");
運行結果:
<3>[ 124.050211] -----work_func----- //work_func有打印
<3>[ 124.244364] -----work_func-----
<3>[ 124.341765] -----work_func-----
<3>[ 124.537000] -----work_func-----
<3>[ 124.630770] -----work_func-----
<3>[ 124.801644] -----test_init----- //test_init有打印
<3>[ 124.825084] -----work_func-----
…
…
…
一直打印log
==========================================================================
總結:
使用create_workqueue創建的工作隊列在工作執行函數work_func中循環調用printk會導致系統卡死,是因為create_workqueue創建工作隊列時在每個cpu上都創建了worker_thread內核線程,worker_thread線程處理的事務能夠並行化,導致所有的cpu都被printk函數所占用,系統無法調用其他的進程,所以系統出現卡死並且無任何log信息打印
而使用create_singlethread_workqueue創建的工作隊列只在一個cpu上創建worker_thread內核線程,即使該cpu一直被printk占用也還有其他的cpu可以繼續調用其他的進程,所以能夠一直打印log
附:
推薦一篇工作隊列講的挺不錯的博客:http://bgutech.blog.163.com/blog/static/18261124320116181119889/