Linux 设备驱动系列 (15) —— 创建自定义工作队列
关注微信公众号:Linux 内核拾遗
前面介绍了 Linux Workqueue 的其中一种实现方式——使用全局工作队列。在这种实现方式下,开发者无需创建任何 workqueue 或者 worker 线程,只需要初始化任务(work)即可。
本文介绍另一种 Linux Workqueue 的实现方式,即创建自定义的工作队列。
1 struct workqueue_struct
struct workqueue_struct
是 Linux 内核中用于表示工作队列的结构体。工作队列允许将需要延迟执行的工作从中断上下文移到进程上下文中执行,这样可以避免在中断上下文中进行复杂和耗时的操作。
struct workqueue_struct
的定义在内核源代码中的 include/linux/workqueue.h
文件中。以下是简化的结构体定义:
list:用于将多个工作队列链接在一起。
name:工作队列的名称。
cpu_wq:指向每个 CPU 的工作队列结构的指针。工作队列通常是按 CPU 分布的,以便于在多处理器系统上并行执行。
另外,struct work_struct
表示工作/任务本身,它需要被添加到工作队列struct workqueue_struct
中才会被调度和执行。
2 创建/销毁工作队列
可以使用 create_workqueue 宏来创建一个 workqueue,结果返回struct workqueue_struct
的引用,随后可以使用 destroy_workqueue 宏来销毁该 workqueue:
此外,可以使用 create_singlethread_workqueue 函数来创建一个单线程的 Workqueue,其中的所有工作项将在同一个内核线程中执行,这非常适合于需要按顺序执行任务的情况。
create_workqueue 和 create_singlethread_workqueue 这两个宏底层都是调用 alloc_workqueue 这个函数。
其中:
fmt:创建工作队列的 printf 格式的名称。
flags:WQ_*参数,用于指定工作队列的行为和属性。
max_active:最大同时处理的工作项的数量。
下面是一些常用的 WQ_*参数:
WQ_UNBOUND:工作队列中的工作项由不绑定到任何特定 CPU 的特殊工作池(unbound worker-pool)处理,该工作队列就像一个简单的执行上下文提供者,没有并发管理,它会尽可能快地启动对工作项的处理。Unbound workqueue 牺牲了局部性,但是适合于以下的场景:
并发程度波动较大的场景,因为使用 Bound workqueue 可能会在不同的 CPU 上创建大量很少使用的工作线程。
长时间运行的 CPU 密集型工作负载,这些负载可以由系统调度程序更好地管理。
WQ_FREEZABLE:在系统挂起(比如待机或休眠)时,这种工作队列会停止接收新任务,并等待当前的任务完成;在系统恢复时,再继续处理新任务。
WQ_MEM_RECLAIM:这种工作队列在系统内存非常紧张的时候仍然能够保证有线程执行任务,适合于在内存不足时也要执行的任务,例如内存回收操作。
WQ_HIGHPRI:高优先级工作队列中的工作项被排入目标 CPU 的高优先级工作池,并且由具有较高 nice 级别的工作线程处理。正常和高优先级工作池不会互相影响,因为每个工作池维护其独立的工作线程池,并在其工作线程之间实现并发管理。
WQ_CPU_INTENSIVE:CPU 密集型任务不会妨碍其他任务的执行,确保所有任务都能被调度执行。
3 往工作队列添加工作项
工作项struct work_struct
初始化完成后,接下来就是要将其添加到工作队列中。Linux 内核提供了以下几种方法。
3.1 queue_work
queue_work 保证工作队列的任务会尽量在提交任务的那个 CPU 上执行,以保持任务的局部性(locality)。但是,如果那个 CPU 不可用(比如宕机或被系统禁用),任务会由其他 CPU 处理。这种机制可以确保任务不会因为某个 CPU 不可用而无法执行。
3.2 queue_work_on
queue_work_on 会将当前任务提交到特定的 CPU 上执行。
3.3 queue_delayed_work
queue_delayed_work 会在任务提交到工作队列之前等待一段时间,由 delay 参数来指定。
3.4 queue_delayed_work_on
queue_delayed_work 会在任务提交到特定的 CPU 上执行之前等待一段时间,由 delay 参数来指定。
4 完整代码演示
kernel_driver.c
代码编译运行,结果如下:
关注微信公众号:Linux 内核拾遗
版权声明: 本文为 InfoQ 作者【Linux内核拾遗】的原创文章。
原文链接:【http://xie.infoq.cn/article/4682c4e28bc04bdffde0e372e】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论