创建推后的工作
INIT_WORK(struct work_struct *work, void(* func)(void *), void *data); 工作队列处理函数 void work_handler(void *data); 对工作进行调度 schedule_work(&work); 延后一段时间后再执行 schedule_delayed_work(&work, delay); 下半部 上下文 顺序执行保障 软中断 中断 没有 tasklet 中断 同类型不能同时执行 工作队列 进程 没有(和进程上下文被一样调度) 《linux kernel development》 P93 如果进程上下文并不是必须的条件 --- 明确点说,就是如果并不需要睡眠 --- 那么软中断tasklet可能更合适。工作队列造成的开销最大,因为它牵扯到内核线程甚至是上下文切换,这并不是说工作队列的效率低,如果每秒钟有几千次中断,就像网络子系统时常经历的那样,那么采用其他的机制可能更合适一些。 使用tasklet的一个好处在于它自己负责执行的序列化保障: 两个相同类型的tasklet不允许同时执行,即使在不同的处理器上也不行。tasklet之间的同步(就是当两个不同类型的tasklet之间共享同一数据时)需要正确使用锁机制。
工作队列概述
工作队列的实现 工作者线程 工作队列子系统是一个用于创建内核线程的接口,通过它创建的进程负责执行由内核其他部分排到队列里的任务。它创建的这些内核线程被称作工作者线程(worker thread)。工作队列可以让你的驱动程序创建一个专门的工作者线程来处理需要推后的工作。不过,工作队列子系统提供了一个默认的工作者线程来处理这些工作。因此,工作队列最基本的表现形式就转变成了一个把需要推后执行的任务交给特定的通用线程这样一种接口。 默认的工作者线程叫做events/n,这里n是处理器的编号,每个处理器对应一个线程。比如,单处理器的系统只有events/0这样一个线程。而双处理器的系统就会多一个events/1线程。 默认的工作者线程会从多个地方得到被推后的工作。许多内核驱动程序都把它们的下半部交给默认的工作者线程去做。除非一个驱动程序或者子系统必须建立一个属于它自己的内核线程,否则最好使用默认线程。不过并不存在什么东西能够阻止代码创建属于自己的工作者线程。如果你需要在工作者线程中执行大量的处理操作,这样做或许会带来好处。处理器密集型和性能要求严格的任务会因为拥有自己的工作者线程而获得好处。 |