在Linux操作系统中,工作队列(work queue)是Linux kernel中将工作推后执行的一种机制。这种机制和BH或Tasklets不同之处在于工作队列是把推后的工作交由一个内核线程去执行,因此工作队列的优势就在于它允许重新调度甚至睡眠。
Nuttx操作系统中工作队列的实现和在Linux中类似,Nuttx在内核中创建了内核线程,用于调度执行工作队列中的任务,在工作队列中允许任务睡眠。
Nuttx中工作队列内核线程有高低两种优先级,高优先级的工作队列用于执行一些优先级比较高的任务,比如将内存buffer中的数据换出到sd卡上。低优先的任务做一些相对不是很紧迫的工作,比如内存片回收。
本节首先介绍工作中队列涉及到的数据结构,然后以高优先级工作队列为例,说明工作队列线程的创建,添加任务到工作队列,工作队列任务处理。
数据结构
工作队列
struct hp_wqueue_s
{
systime_t delay; /* Delay between polling cycles (ticks) */
struct dq_queue_s q; /* The queue of pending work */
struct kworker_s worker[1]; /* Describes the single high priority worker */
};
struct lp_wqueue_s
{
systime_t delay; /* Delay between polling cycles (ticks) */
struct dq_queue_s q; /* The queue of pending work */
/* Describes each thread in the low priority queue's thread pool */
struct kworker_s worker[CONFIG_SCHED_LPNTHREADS];
};
- delay是线程poll的周期。每次当工作队列poll一次工作队列上的任务,睡眠delay时间。如果工作队列的处理方式采用周期性的poll方式,信号可以唤醒工作队列线程,如果线程处在休眠状态。如果工作队列的处理方式采用信号中断的方式,那么只有当工作队列线程收到信号之后才会从睡眠等待中被唤醒,否则一直处于睡眠状态。
- 链表头q将任务链接在链表上
- worker数组中的每一项代表一个线程。高优先级工作队列只创建一个线程,低优先级的工作队列至少创建了一个工作线程。
注意: 为了展现代码逻辑,文中忽略了对临界资源的保护代码
工作队列线程
struct kworker_s
{
pid_t pid; /* The task ID of the worker thread */
volatile bool busy; /* True: Worker is not available */
};
- pid记录了工作队列中某个线程的pid
- 当busy为真时,表明该线程当前处于运行状态,不能接受信号。
工作任务
struct work_s
{
struct dq_entry_s dq; /* Implements a doubly linked list */
worker_t worker; /* Wor