工作队列

来源:互联网 发布:mac怎么用word文档 编辑:程序博客网 时间:2024/05/21 09:20

1 "工作队列"用途
 工作队列用途跟tasklet相似,在中断处理时将一些非紧急的任务留到工作队列中完成,而紧急的任务则在硬中断服务程序中完成。
 但工作队列与tasklet还是有很大的区别:
 1)工作队列函数在一个特殊内核进程的上下文中运行;
 2)tasklet会在很短的时间段内很快执行,且以原子模式执行;
    而工作队列函数具有更长的延迟并且不需要原子模式;
 3)工作队列函数可以休眠;

2 "工作队列"结构
  注意:2.6.20之后,工作队列的数据结构发生了不少变化,这里列出的接口与数据结构是基于3.2.1的。

  1. #include<linux/workqueue.h>
  2. struct workqueue_struct {/*定义在kernel/workqueue.c*/}; /*工作队列结构*/
  3. /*
  4.  * 向工作队列提交一个任务的任务结构
  5.  */
  6. struct work_struct {
  7.     atomic_long_t data;
  8.     struct list_head entry;
  9.     work_func_t func;     /*work_func_t 定义如下*/
  10.     /*省略其他成员变量*/
  11. }
  12. typedef void (*work_func_t)(struct work_struct *work);
  13. 3 "工作队列"接口
     这里只列出一些重要的接口,如果想查看更多接口,可参看"linux/workqueue.h"文件。

     3.1 创建工作队列
  1. /*这两个是宏,使用时name不用加双引号,这里这样写只是更好地表达该宏的用途*/
  2. struct workqueue_struct *create_workqueue(const char *name) /*在系统中的每个处理器上
  3.                                                               为该工作队列创建专用线程*/
  4. struct workqueue_struct *create_singlethread_workqueue(const char *name) /*只创建一个专用线程*/
  5. 3.2 创建工作(work_struct)
  1. DECLARE_WORK(name,func); /*定义名为name的work_struct类型变量,使用时name不用加双引号,
  2.                            func是work_func_t类型*/

  3. INIT_WORK(struct work_struct *work,work_func_t func); /*添充work变量,首次构造该结构时使用*/
  4. INIT_DELAYED_WORK(struct work_struct *work,work_func_t func); 
  5. PREPARE_WORK(struct work_struct *work,work_func_t func); /*如果工作已提交到工作队列时,而只需修改该结构时使用*/

3.3 提交工作到工作队列

  1. int queue_work(struct workqueue_struct *wq, struct work_struct *work);
  2. int queue_delayed_work(struct workqueue_struct *wq, struct_work *work, unsigned long delay); /*工作至少会被延迟delay后被执行*/

3.4 取消工作

  1. int cancel_delayed_work(struct work_struct *work); /*如果工作在开始执行前被取消,则返回非零值*/
  2. void flush_workqueue(struct workqueue_struct *wq); /*该函数返回后,任何在该函数调用之前被提交的工作都不会在系统任何地方运行*/
  3. 3.5 销毁"工作队列"
  4. void destroy_workqueue(struct workqueue_struct *queue);

4 共享队列
 如果对工作队列使用不是很频繁的话,则可以使用内核提供的共享的默认队列;需要注意的是,使用该共享队列时不应该长期独占它,而且任务可能需要等待更长的时间后才被执行;一般情况下,推荐使用共享队列。

 共享队列接口

  1. int schedule_work(struct work_struct *work); /*提交工作任务到共享队列*/
  2. int schedule_delayed_work(struct work_struct *work,unsigned long delay);
  3. void flush_scheduled_work(void);
  4. 5 示例代码
     这里只是演示如何使用“工作队列”,并没有在中断处理中使用。
#include <linux/module.h>#include <linux/init.h>#include <linux/workqueue.h>MODULE_LICENSE("Dual BSD/GPL");MODULE_AUTHOR("Kozo");struct my_struct{char *name;struct work_struct my_work;};static void display(struct work_struct *work){/*获取结构体的首地址,在知道一个结构体成员的时候获取整个结构体的时候用。知道一个申明了的结构体的一个参数就可以知道这个结构体的首地址。*/
/*container_of在Linux Kernel中的应用非常广泛,它用于获得某结构中某成员的入口地址,这里是获取结构体 chip 的地址*/         /*Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址*/
struct my_struct *my_name = container_of(work,struct my_struct, my_work);printk(KERN_DEBUG"name = %s\n",my_name->name);}static struct workqueue_struct *my_wq;static struct my_struct my_name;static int __init demo_init(void){printk("init the main");my_wq = create_workqueue("my wq");my_name.name = "Jake";
INIT_WORK(&(my_name.my_work), display);//display()加到工作上去,queue_work(my_wq,&(my_name.my_work));//将工作加到队列上去
return 0;}static void __exit demo_exit(void){printk(KERN_DEBUG"Goodbye\n");destroy_workqueue(my_wq);}module_init(demo_init);module_exit(demo_exit);


 5.2 使用共享队列 

#include <linux/module.h>#include <linux/init.h>#include <linux/workqueue.h>MODULE_LICENSE("Dual BSD/GPL");MODULE_AUTHOR("Kozo");struct my_struct{char *name;struct work_struct my_work;};static struct my_struct my_name={.name="Kozo",};static void display(struct work_struct *work){struct my_struct *my_name = container_of(work,struct my_struct, my_work);printk(KERN_DEBUG"name = %s\n",my_name->name);}static int __init demo_init(void){//my_name.name = "Kozo";INIT_WORK(&(my_name.my_work), display);//创建工作队列schedule_work(&(my_name.my_work));//共享工作队列return 0;}static void __exit demo_exit(void){printk(KERN_DEBUG"Goodbye\n");flush_scheduled_work();}module_init(demo_init);module_exit(demo_exit);


自己修改的共享队列实例:

#include <linux/module.h>#include <linux/init.h>#include <linux/workqueue.h>MODULE_LICENSE("Dual BSD/GPL");MODULE_AUTHOR("Kozo");struct my_struct{char *name;struct work_struct my_work;};static struct my_struct my_name={.name="Kozo",};static void display(struct work_struct *work){struct my_struct *zl_name ;printk("exec schedule_work\n");zl_name= container_of(work,struct my_struct, my_work);//获取结构体的首地址,在知道一个结构体成员的时候获取整个结构体的时候用。知道一个申明了的结构体的一个参数就可以知道这个结构体的首地址。printk("name\n");printk("name = %s\n",zl_name->name);printk("name=\n");}static int __init demo_init(void){INIT_WORK(&(my_name.my_work), display);//创建工作队列,myname结构体要已经定义。schedule_work(&(my_name.my_work));//共享工作队列return 0;}static void __exit demo_exit(void){printk(KERN_DEBUG"Goodbye\n");flush_scheduled_work();}module_init(demo_init);module_exit(demo_exit);

 

共享工作队列 有延时 实例:

#include <linux/module.h>#include <linux/init.h>#include <linux/workqueue.h>MODULE_LICENSE("Dual BSD/GPL");MODULE_AUTHOR("Kozo");struct my_struct{char *name;struct delayed_work my_work;};static struct my_struct my_name={.name="Kozo",};static void display(struct work_struct *work){struct my_struct *zl_name ;printk("exec schedule_work\n");zl_name= container_of(work,struct my_struct, my_work);//获取结构体的首地址,在知道一个结构体成员的时候获取整个结构体的时候用。知道一个申明了的结构体的一个参数就可以知道这个结构体的首地址。printk("name = %s\n",zl_name->name);schedule_delayed_work(&(my_name.my_work), 1000);//共享工作队列}static int __init demo_init(void){INIT_DELAYED_WORK_DEFERRABLE(&my_name.my_work, display);schedule_delayed_work(&my_name.my_work, 1000);//共享工作队列return 0;}static void __exit demo_exit(void){printk(KERN_DEBUG"Goodbye\n");flush_scheduled_work();}module_init(demo_init);module_exit(demo_exit);