工作队列

21 篇文章 2 订阅
2 篇文章 0 订阅
Linux 2.6内核使用了不少工作队列来处理任务,他在使用上和 tasklet最大的不同是工作队列的函数可以使用休眠,而tasklet的函数是不允许使用休眠的。

工作队列的使用又分两种情况,一种是利用系统共享的工作队列来增加自己的工作,这种情况处理函数不能消耗过多时间,这样会影响共享队列中其他任务的处理;另一种是创建自己的工作队列并添加工作

(一)利用系统共享的工作队列添加工作

第一步:声明或编写一个工作处理函数

void my_func();

第二步:创建一个工作结构体变量,并将处理函数和参数的入口地址赋给这个工作结构体变量
DECLARE_WORK(my_work,my_func,&data); //编译时创建名为my_work的结构体变量并把函数入口地址my_func和参数地址&data赋给它;

假如不想要在编译时创建,就用DECLARE_WORK()创建并初始化工作结构体变量,

也可以在程序运行时初始化一个工作队列可用INIT_WORK()创建
struct work_struct my_work;                       //创建一个名为my_work的结构体变量,创建后才能使用INIT_WORK()
INIT_WORK(&my_work,my_func,&data);          //初始化已经创建的my_work,其实便是往这个结构体变量中添加处理函数的入口地址和data的地址,通常在驱动的open函数中完成

第三步:将工作结构体变量添加入系统的共享工作队列
schedule_work(&my_work);                                     //添加入队列的工作完成后会自动从队列中删除
schedule_delayed_work(&my_work,tick);                    //延时tick个滴答后再提交工作


(二)创建自己的工作队列来添加工作
第一步:声明工作处理函数和一个指向工作队列的指针
void my_func();
struct workqueue_struct *p_queue;

第二步:创建自己的工作队列和工作结构体变量(通常在open函数中完成)

创建, 使用一个下列的 2 个函数:

struct workqueue_struct *create_workqueue(const char *name);
struct workqueue_struct *create_singlethread_workqueue(const char *name);

每个工作队列有一个或多个专用的进程("内核线程"), 它运行提交给这个队列的函数. 如果你使用 create_workqueue, 你得到一个工作队列它有一个专用的线程在系统的每个处理器上. 在很多情况下, 所有这些线程是简单的过度行为; 如果一个单个工作者线程就足够, 使用 create_singlethread_workqueue 来代替创建工作队列

eg:
p_queue= create_workqueue ("my_queue"); //创建一个名为my_queue的工作队列并把工作队列的入口地址赋给声明的指针
struct work_struct my_work;
INIT_WORK(&my_work,my_func,&data);
//创建一个工作结构体变量并初始化,和第一种情况的办法一样

第三步:将工作添加入自己创建的工作队列等待执行
queue_work (p_queue,my_work); //作用与schedule_work()相似,不同的是将工作添加入p_queue指针指向的工作队列而不是系统共享的工作队列

第四步:删除自己的工作队列
destroy_workqueue (p_queue);//基本是在close函数中删除


===========================================================================================================

工作队列 API 比微线程稍复杂,主要是因为它支持很多选项。 我们首先探讨一下工作队列,然后再看一下任务和变体。

通过 图 3 可以回想工作队列的核心结构体是队列本身。 该结构体用于将任务安排出 top half ,进入 bottom half ,从而延迟它的执行。 工作队列通过宏调用生成 create_workqueue,返回一个 workqueue_struct 参考值。 可以通过调用函数 destroy_workqueue 来远程遥控工作队列(如果需要):

struct workqueue_struct *create_workqueue( name );
void destroy_workqueue( struct workqueue_struct * );

通过工作队列与之通信的任务可以由结构体 work_struct 来定义。 通常,该结构体是用来进行任务定义的结构体的第一个元素(后面有相关例子)。 工作队列 API 提供三个函数来初始化任务(通过一个事先分配的缓存); 参见 清单 6。 宏 INIT_WORK 提供必需的初始化数据以及处理程序函数的配置(由用户传递进来)。 如果开发人员需要在任务被排入工作队列之前发生延迟,可以使INIT_DELAYED_WORK  INIT_DELAYED_WORK_DEFERRABLE

清单6  任务初始化
INIT_WORK( work, func );
INIT_DELAYED_WORK( work, func );
INIT_DELAYED_WORK_DEFERRABLE( work, func );
单 7. 工作队列函数 

任务结构体的初始化完成后,接下来要将任务安排进工作队列。 可采用多种方法来完成这一操作(参见 清单 7)。 首先,利用queue_work 简单地将任务安排进工作队列(这将任务绑定到当前的 CPU)。 或者,可以通过 queue_work_on 来指定处理程序在哪个 CPU 上运行。 两个附加的函数为延迟任务提供相同的功能(其结构体装入结构体 work_struct 之中,并有一个 计时器用于任务延迟 )。

清单7  将任务安排进工作队列
				
int queue_work( struct workqueue_struct *wq, struct work_struct *work );
int queue_work_on( int cpu, struct workqueue_struct *wq, struct work_struct *work );

int queue_delayed_work( struct workqueue_struct *wq,struct delayed_work *dwork, 				unsigned long delay );
int queue_delayed_work_on( int cpu, struct workqueue_struct *wq,						struct delayed_work *dwork, unsigned long delay );
单 8. 内核全局工作队列函数 

也可以使用全局的内核全局工作队列,利用 4 个函数来为工作队列定位。 这些函数(见 清单 8)模拟 清单 7,只是不需要定义工作队列结构体。

				
int schedule_work( struct work_struct *work );
int schedule_work_on( int cpu, struct work_struct *work );

int scheduled_delayed_work( struct delayed_work *dwork, unsigned long delay );
int scheduled_delayed_work_on( int cpu, struct delayed_work *dwork, unsigned long delay );

还有一些帮助函数用于清理或取消工作队列中的任务。想清理特定的任务项目并阻塞任务, 直到任务完成为止, 可以调用flush_work 来实现。 指定工作队列中的所有任务能够通过调用 flush_workqueue 来完成。 这两种情形下,调用者阻塞直到操作完成为止。 为了清理内核全局工作队列,可调用 flush_scheduled_work

int flush_work( struct work_struct *work );
int flush_workqueue( struct workqueue_struct *wq );
void flush_scheduled_work( void );

没有在处理程序当中执行的任务可以被取消。 调用 cancel_work_sync 将会终止队列中的任务或者阻塞任务直到回调结束(如果处理程序已经在处理该任务)。 如果任务被延迟,可以调用 cancel_delayed_work_sync

int cancel_work_sync( struct work_struct *work );
int cancel_delayed_work_sync( struct delayed_work *dwork );

最后,可以通过调用 work_pending 或者 delayed_work_pending 来确定任务项目是否在进行中。

work_pending( work );
delayed_work_pending( work );


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值