现在的位置: 首页 > 综合 > 正文

Linux/Android工作队列(workqueues)

2013年08月03日 ⁄ 综合 ⁄ 共 3955字 ⁄ 字号 评论关闭

基本概念

        工作队列(work queue)是Linux内核中将操作延期执行的一种机制。因为它们是通过守护进程在用户上下文执行,函数可以睡眠的时间,与内核是无关的。在内核版本2.5开发期间,设计了工作队列,用以替换此前的keventd机制。

         这种机制和BH或Tasklets不同之处在于工作队列是把延期的工作交由一个内核线程去执行,因此工作队列的优势就在于它允许重新调度甚至睡眠。

         每个工作队列多有一个数组,数据元素的数目与内核处理器core的数目相同,每个数据元素都列出来将要延期执行的任务。

          对于每个工作队列来说,内核都会创建一个新的内核守护线程,延期任务使用上下文描述的等待队列机制,在守护进程的上下午执行。

工作队列 (workqueues)

在讨论之前,先定义几个内核中使用工作队列时用到的术语方便后面描述。

  • workqueues:所有工作项被 ( 需要被执行的工作 ) 排列于该队列,因此称作工作队列 (workqueues) 。
  • worker thread:工作者线程 (worker thread) 是一个用于执行工作队列中各个工作项的内核线程,当工作队列中没有工作项时,该线程将变为 idle 状态。
  • single threaded(ST)::工作者线程的表现形式之一,在系统范围内,只有一个工作者线程为工作队列服务
  • multi threaded(MT):工作者线程的表现形式之一,在多 CPU 系统上每个 CPU 上都有一个工作者线程为工作队列服务

queue_delayed_work和queue_work区别和使用

一、参考文献:

1)http://www.linuxidc.com/Linux/2011-08/41655.htm

queue_delayed_work的使用过程如下:

--> 定义workqueue: struct workqueue_struct *test_workqueue;                                      // 定义在: kernel/workqueue.c

    --> 定义workqueue要做的delayed工作:struct delayed_work test_delayed_work;       // 定义在: include/linux/workqueue.h

    --> 初始化workqueue:INIT_DELAYED_WORK(test_workqueue, test_delayed_work);    // 定义在:include/linux/workqueue.h

    --> 创建线程queue并加以名字:test_workqueue = create_singlethread_workqueue("name_of_this_queue");

    --> 运行queue:queue_delayed_work(test_workqueue, test_delayed_work, delay_time);  // 定义在:kernel/workqueue.c, 其中delay_time是延迟多少时间来运行queue。

注: 在delayed_work中一定要再次将delayed_workqueue加入queue中,即再次运行queue_delayed_work。否则,此queue只运行一次。

2)http://blog.csdn.net/zchill/article/details/7076561
一个INIT_WORK()对应queue_work、schedule_work(),一个INIT_DELAYED_WORK()对应queue_delayed_work、schedule_delayH

后者就是专门用于可以有延时的,而前者就是没有延时的

关于工作队列机制,咱们还会用到另外两个函数,它们是cancel_delayed_work(struct delayed_work *work)和flush_scheduled_work().其中

cancel_delayed_work()的意思不言自明,对一个延迟执行的工作来说,这个函数的作用是在这个工作还未执行的时候就把它给取消掉.而flush_scheduled_work()的作用,是为了防止有竞争条件的

(例:比如说它先想好了,下午3点执行队列里的第N个成员,可是您突然把第N-1个成员给取走了,那您说这是不是得出错?所以,为了防止您这种唯恐天下不乱的人做出冒天下之大不韪的事

3)http://blog.csdn.net/heanyu/article/details/6899679

内核队列、定时器、阻塞、休眠

API

1) INIT_WORK(_work, _func)

初始化指定工作,目的是把用户指定的函数_func赋给work_structfunc

2) int schedule_work(struct work_struct *work)------>> queue_work

对工作进行调度,即给定工作的处理函数提交给缺省的工作队列和工作者线程。工作者线程本质上是一个普通的内核线程,在默认情况下,每个CPU均有一个类型为“events”的工作者线程,当调用schedule_work时,这个工作者线程会被唤醒去执行工作链表上的所有工作。

3) int schedule_delayed_work(struct work_struct *work, unsigned long delay) ---> queue_delayed_work --> queue_work

延迟执行工作,与schedule_work类似。

4) void flush_scheduled_work(void)

刷新缺省工作队列。此函数会一直等待,直到队列中的所有工作都被执行。

5) int cancel_delayed_work(struct work_struct *work)
   flush_scheduled_work并不取消任何延迟执行的工作,因此,如果要取消延迟工作,应该调用cancel_delayed_work

4)http://bbs.chinaunix.net/thread-1927165-1-1.html

相对于create_singlethread_workqueue, create_workqueue同样会分配一个wq的工作队列,但是不同之处在于,对于多CPU系统而言,对每一个CPU,都会为之

创建一个per-CPU的cwq结构,对应每一个cwq,都会生成一个新的worker_thread进程。但是当用queue_work向cwq上提交work节点时,是哪个CPU调用该函数,那么便向该CPU对应的cwq上的worklist上增加work节点。

 

 

二、简略程序:

1)queue_work

create_workqueue("goodix_wq");//加载ko时init或probe时初始化

INIT_WORK(&ts->work, goodix_ts_work_func);//初始化工作队列

 queue_work(goodix_wq, &ts->work);//此处需要request_irq中断触发或者是timer定时器触发, 调度执行并不等于立刻执行。而是指示

                                                                      //worker_thread在下次处理工作队列的时候执行该工作;

destroy_workqueue(goodix_wq);//卸载ko退出或remove时注销

 

2)queue_work

create_singlethread_workqueue("proximity");///加载ko时init或probe时初始化    //单线程,此处也可使用create_workqueue();如前文引文4)内容

INIT_DELAYED_WORK(&ip->work, rohm_proximity_work));//初始化工作队列

queue_delayed_work(data->work_queue, &data->work,msecs_to_jiffies(ms));//同前面queue_work区别在于:自带延时功能,即定时器功能

                                                          //调用此函数后,经过ms时间后就会自动进入工作队伍函数,此处为rohm_proximity_work() 

cancel_rearming_delayed_workqueue(proximity_data.work_queue, &proximity_data.work);//以下两句停止该队列时使用,比如此处psensor在脸远离时通过
flush_workqueue(proximity_data.work_queue);                                                                              //file_operations的.release调用此两句    destroy_workqueue

 

destroy_workqueue(proximity_data.work_queue);//卸载ko退出或remove时注销 

附:queue_work()和schedule_work(&vibe_work);前者比后者多了个work_queue参数,即后者无需创建create_workqueue()动作

抱歉!评论已关闭.