android底层驱动学习之工作队列work_queue相关参数
今早看了与工作队列有关的相关知识,下面总结下:
1. 什么是工作队列:
工作队列(work queue)是另外一种将工作推后执行的形式。工作队列可以把工作推后,交由一个内核线程去执行—这个下半部分总是会在进程上下文执行,但由于是内核线程,其不能访问用户空间。最重要特点的就是工作队列允许重新调度甚至是睡眠。
实际上,工作队列的本质就是将工作交给内核线程处理,因此其可以用内核线程替换。但是内核线程的创建和销毁对编程者的要求较高,而工作队列实现了内核线程的封装,不易出错,所以我们也推荐使用工作队列。
工作队列和tasklet都是可以将工作推后的形式
2.首先是不是要先来看下工作队列的数据结构,如下:
l struct work_struct //一个工作的结构体
{
atomic_long_tdata;//工作处理函数的参数
structlist_head entry;
work_func_tfunc;//工作处理函数
#ifdef CONFIG_LOCKDEP
structlockdep_map lockdep_map;
#endif
};
l struct workqueue_struct //一个工作队列
{
struct cpu_workqueue_struct *cpu_wq;//创建对应的cpuworkqueue,叫做工作者线程
struct list_head list;
const char *name; /*workqueue name*/
int singlethread; /*是不是单线程 - 单线程我们首选第一个CPU-0表示采用默认的工作者线程event*/
int freezeable; /* Freeze threads during suspend */
int rt;
};
3.那么如何去创建和执行一个工作呢?
首先创建一个工作,有静态和动态两种方法:
l 静态:
DECLARE_WORK(name,function);//定义正常执行的工作项
DECLARE_DELAYED_WORK(name,function);//定义延后执行的工作项
l 动态:
INIT_WORK(&data->touch_event_work,fts_touch_irq_work)
INIT_DELAYED_WORK(&led_work,s0340_ledtime_scanf);
4.接下来就是创建工作队列了
l create_singlethread_workqueue("fts_wq")
用于创建workqueue,只创建一个内核线程。
l create_workqueue("fts_wq")
用于创建一个workqueue队列,为系统中的每个CPU都创建一个内核线程。
5.将创建好的工作加入到工作队列中并执行
l queue_work(fts_ts->ts_workqueue,&fts_ts->touch_event_work);
调度执行一个指定workqueue中的任务
l queue_delayed_work
延迟调度执行一个指定workqueue中的任务,功能与queue_work类似,输入参数多了一个delay。
6.也可以单独执行一个工作:
l schedule_work(&fts_ts->touch_event_work)
调度执行一个具体的任务,执行的任务将会被挂入Linux系统提供的workqueue——keventd_wq
l schedule_delayed_work
延迟一定时间去执行一个具体的任务,功能与schedule_work类似,多了一个延迟时间
那你是不是会有一个问题:工作队列和tasklet有什么区别,二者都是可以处理进程上下文的?
答:Linux2.6内核使用了不少工作队列来处理任务,他在使用上和 tasklet最大的不同是工作队列的函数可以使用休眠,而tasklet的函数是不允许使用休眠的。
另外,内核必须挂载文件系统才可以使用工作队列。我的理解是:工作队列也属于调度,如果内核挂了,他就不调度了,当然就不能用工作队列了。
工作队列的使用又分两种情况,一种是利用系统共享的工作队列来添加自己的工作,这种情况处理函数不能消耗太多时间,这样会影响共享队列中其他任务的处理;另外一种是创建自己的工作队列并添加工作。
Tasklet其实和软中断很像,首先通过在驱动初始化时做tasklet_init注册tasklet,然后在中断处理程序结束前调用tasklet_schedule来使能tasklet。
那么最后如何选择这两种都可以推后的形式呢?
l 如果推后执行的任务需要睡眠,那么只能选择工作队列;
l 如果推后执行的任务需要延时指定的时间再触发,那么使用工作队列,因为其可以利用timer延时;
l 如果推后执行的任务需要在一个tick之内处理,则使用软中断或tasklet,因为其可以抢占普通进程和内核线程;
l 如果推后执行的任务对延迟的时间没有任何要求,则使用工作队列,此时通常为无关紧要的任务。
实际上,工作队列的本质就是将工作交给内核线程处理,因此其可以用内核线程替换。但是内核线程的创建和销毁对编程者的要求较高,而工作队列实现了内核线程的封装,不易出错,所以我们也推荐使用工作队列。
、
PS: ,linux调度是以进程(或者说线程)来的,即做调度是不同进程上下文的切换.
7,而可以看到软中断逻辑不属于任何进程,所以才不能睡眠,因为一旦睡眠,cpu切换出去,就切不回来了(和6一起理解).并不是说无法做到在软/硬中断睡眠,只是目前Linux的实现就是这样的,不允许你这么做,要是这么做了,你就等死.