一、前言
Zephyr的work队列机制跟Linux的相似,用于实现一些耗时操作,zephyr的work队列是基于线程的,原理类似于一个线程一直在等待work队列发来的工作项,这个工作项是初始化work项时候指定的函数,当有工作项被调度时线程就是执行这个函数,当有多个工作项提交队列执行时,队列按照FIFO(先进先出)形式调度。一个work项在使用前需要初始化,主要是关联处理函数,标记工作项为挂起状态,等着被线程调度。一个work项可以在ISR或者线程中被提交,提交后work项就会被添加到work queue队列中。
二、延时工作项–Delayed work
如字面意思,就是按照指定时间延时后执行的工作项。当Delayed work被提交时并不会立马被添加到work queue中,而是在等待一个指定延时的时间后才被添加。一个延时工作项通过struct k_delayed_work去定义,并通过 k_delayed_work_init()去初始化,通过调用k_delayed_work_submit()把延时工作项提交给系统工作队列,通过k_delayed_work_submit_to_queue()把延时工作项提交给用户自己定义的工作队列。当想取消一个超时工作项,可以使用 k_delayed_work_cancel()函数,但是需注意,取消只能在工作项指定的超时没发生之前,否则不能被取消。
三、poll工作项
该工作项是和POLL机制相关的工作项,他是在一个线程中等待多个内核对象有效比如信号量、FIFO等。使用k_work_poll_init初始化一个poll工作项,并绑定一个处理函数,使用k_work_poll_submit提交该工作项,当监视的资源或者轮询信号触发或者超时发生时,队列将会调度一开始关联的处理函数,当工作项提交以后,内核就开始观察轮询事件指定的对象。,一旦观察的对象有一个处于更改状态,工作项就会立刻把工作项加到队列中等待调度处理。在内核观察到观察对象变更之前的这段时间,工作项可以被随时取消。
四、系统工作队列System Workqueue
work是被提交到work queue的一个元素,当内核使能了工作队列功能,内核就会自动创建一个system workqueuede 的工作队列,这个队列用户可以通过manuconfig去配置。当用户没有自定义队列时work默认提交到这个队列去调度执行。补充一点的是,虽然zephyr支持用户自定义工作队列,但是自定义队列需要消耗大量的资源,RAM、FLASH等,并且zephyr一般是运行在资源有限的系统上,所以并不推荐自定义工作队列。
五、用户定义一个工作队列
#define MY_STACK_SIZE 512
#define MY_PRIORITY 5
K_THREAD_STACK_DEFINE(my_stack_area, MY_STACK_SIZE); // 定义一个栈空间
struct k_work_q my_work_q; // 定义一个工作队列
k_work_q_start(&my_work_q, my_stack_area, K_THREAD_STACK_SIZEOF(my_stack_area), MY_PRIORITY); // 初始化工作队列并启动工作队列
六、用户使用工作项
1.普通工作项
struct k_work state_change_work; // 定义一个工作项
/* 定义一个工作项执行函数 */
void state_change_work_handler(struct k_work *work)
{
........
}
k_work_init(&state_change_work, state_change_work_handler); // 初始化工作项
k_work_submit(&state_change_work); // 提交一个工作项到队列
2.poll工作项
static struct k_poll_event change_led_events[1] = {
K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_MSGQ_DATA_AVAILABLE,
K_POLL_MODE_NOTIFY_ONLY,
&change_led_msgq, 0)
}; // 定义轮询观察的对象事件
struct k_work_poll change_led_work; // 定义poll工作项
/ * 定义poll工作项处理函数 * /
void change_led_work_handler(struct k_work *work)
{
........
}
k_work_poll_init(&change_led_work, change_led_work_handler); // 初始化poll工作项
k_work_poll_submit(&change_led_work, change_led_events, ARRAY_SIZE(change_led_events), K_FOREVER); // 提交poll工作项到队列等待调度