Linux内核编程之工作队列(work_queue)的简单使用

Published: 13 Jun 2014 Category: linux

这里对Linux的工作队列(work_queue)不做深层次的挖掘,只对如何使用它以及一些简单的结构做简单地介绍。

Linux源代码(3.0.8)中和工作队列(work_queue)相关的结构主要在

  • include/linux/workqueue.h

这个头文件中,这里就不摘抄了。这里就直接给出例子代码,在结合稍作解释:

#include <linux/module.h>  
#include <linux/init.h>  
#include <linux/workqueue.h>  


static struct work_struct work;  

static void work_handler(struct work_struct *data)  
{  
    printk("just a demo for work queue.\n");  
}  

static int __init workqueue_init(void)  
{  
    printk("init work queue demo.\n");
    INIT_WORK(&work, work_handler);
    schedule_work(&work);  
    return 0;  
}  

static void __exit workqueue_exit(void)  
{  
    printk("exit work queue demo.\n");
}  
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhuqinggooogle@gmail.com");  
module_init(workqueue_init);  
module_exit(workqueue_exit);   

一个简单的工作队列(work_queue)的演示就完成了。我们来编译后,insmod到系统看看:

/mnt/3520d $ insmod hi_work_queue.ko 
init work queue demo
just a demo for work queue.   

从系统中rmmod看一下:

/mnt/3520d $ rmmod hi_work_queue
exit work queue demo.  

如果你对Linux的工作队列(work_queue)有稍微的了解,你看到这里会提问,“我们的工作队列项提交到了哪个工作队列线程上面呢?”,这就得从

  • schedule_work

函数入手。看一下其定义:

/**
 * schedule_work - put work task in global workqueue
 * @work: job to be done
 *
 * Returns zero if @work was already on the kernel-global workqueue and
 * non-zero otherwise.
 *
 * This puts a job in the kernel-global workqueue if it was not already
 * queued and leaves it in the same position on the kernel-global
 * workqueue otherwise.
 */
int schedule_work(struct work_struct *work)
{
    return queue_work(system_wq, work);
}  

这里牵扯到

  • system_wq

这个全局变量,我们来看看他到底是什么。在

  • kernel/workqueue.c

这个文件的底部给出了定义:

system_wq = alloc_workqueue("events", 0, 0);  

看到这就清楚了,刚才是把工作队列项提交了默认的工作线程events上的。那我们自己可以创建一个工作队列线程吗?可以把自己的工作队列项提交到上面吗?当然,可以。下面给出一个demo代码:

#include <linux/module.h>  
#include <linux/init.h>  
#include <linux/workqueue.h>  

static struct workqueue_struct *queue = NULL;  
static struct work_struct work;   
static void work_handler(struct work_struct *data)  
{  
    printk("just a demo for work queue.\n"); 
}  

static int __init workqueue_init(void)  
{  
    queue = create_singlethread_workqueue("workqueue demo");
    if (!queue)  
        return -1;  
    printk("init work queue demo.\n");
    INIT_WORK(&work, work_handler);  
    queue_work("queue", &work);  
    return 0;    
}  

static void __exit workqueue_exit(void)  
{  
       printk("exit work queue demo.\n");
       destroy_workqueue(queue);  
}  
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhuqinggooogle@gmail.com");  
module_init(workqueue_init);  
module_exit(workqueue_exit); 

我们来insmod看一下:

/mnt/3520d $ insmod hi_work_queue.ko 
init work queue demo.
just a demo for work queue.
/mnt/3520d $ 
/mnt/3520d $ ps | grep "workqueue demo"
  728 root         0 SW<  [workqueue demo]  

你会发现多了一个内核线程workqueue demo,这就是我们代码中自己创建的。