用例程解釋create_singlethread_workqueue與create_workqueue的區別


用例程解釋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/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM