工作队列
简介
工作队列(workqueue)是对任务封装的一种用于处理各种工作项(work)的机制,由于处理的对象是用链表连接起来的一个个工作项,在封装的任务中被依次取出来一个个处理,就像队列依次处理一样,所以称为工作队列。
从原理上简单来讲,创建一个工作队列,实际上会创建一个任务;向工作队列上提交工作项,实际上会向该工作队列的链表上添加工作项,注册时可以选择延时或者不延时执行;而工作队列所对应的任务一旦检测到链表上有工作项需要执行,则会调用对应工作项的回调函数。
对于一些简单的功能函数或者不需要不断循环处理的,如果单独创建一个任务来处理就显得有点浪费,此时选择工作队列会更合适。另外工作队列是在任务环境中执行的,可以睡眠,所以针对中断触发的某些事情,也可以把其中某些对时间要求不高的部分放到工作队列里面去处理。
本操作系统提供的工作队列有两种接口。第一种接口,用户可以创建自己的工作队列,自行决定栈大小和任务优先级,然后把需要的工作项提交到工作队列上;另外一种接口,用户不用创建工作队列,而是直接把工作项提交到系统创建的工作队列上。
重要定义及数据结构
结构体
struct os_workqueue
{
os_list_node_t pending_list_head;
os_list_node_t delaying_list_head;
os_work_t *work_current; /* Work in progress on workqueue */
os_task_t *process_task; /* Task on the workqueue to execute work */
os_sem_t process_sem; /* Semaphore for synchronization */
os_bool_t destroy; /* Used to flag whether the workqueue is destroyed */
};
struct os_workqueue参数 | 说明 |
---|---|
pending_list_head | 工作队列上即将执行的工作项链表头 |
delaying_list_head | 工作队列上延时执行的工作项链表头 |
work_current | 工作队列上正在执行的工作项 |
process_task | 工作队列对应的任务 |
process_sem | 信号量,用来通知工作队列的任务有工作项需要处理 |
destroy | 标志,表明该工作队列正在销毁 |
struct os_work
{
os_list_node_t list;
void (*func)(struct os_work *work, void *data);
void *data;
void (*cleanup)(struct os_work *work);
os_work_stage_t stage;
os_uint16_t ref_count;
os_timer_t timer;
os_sem_t sem;
struct os_workqueue *workqueue;
};
struct os_work参数 | 说明 |
---|---|
list | 工作项链表节点,用于挂到工作队列的链表上 |
func | 使用者注册的工作项函数 |
data | 使用者注册的工作项函数的参数 |
cleanup | 使用者注册的清除函数 |
stage | 工作项的状态 |
ref_count | 工作项的引用计数 |
timer | 定时器,用于延时处理的工作项 |
sem | 信号量,用于等待工作项完成 |
API列表
接口 | 说明 |
---|---|
os_workqueue_create | 创建工作队列 |
os_workqueue_destroy | 销毁工作队列 |
os_workqueue_submit_work | 向工作队列提交工作项 |
os_workqueue_cancel_work | 取消工作队列上的指定工作项,若该工作项已经开始运行,会立即返回OS_EBUSY错误码 |
os_workqueue_cancel_work_sync | 以同步方式取消工作队列上的指定工作项,若该工作项已经开始运行,会等待工作项执行完后再返回 |
os_workqueue_cancel_all_work | 取消工作队列上的所有未执行的工作项(包括正在排队的和延时执行的),正在执行的工作项不能取消 |
os_work_init | 初始化工作项 |
os_work_deinit | 反初始化工作项 |
os_submit_work | 向系统维护的工作队列提交工作项 |
os_cancel_work | 取消系统工作队列上的指定工作项,若该工作项已经开始运行,会立即返回OS_EBUSY错误码 |
os_cancel_work_sync | 以同步方式取消系统工作队列上的工作项,如果该工作项已经开始运行,会等待工作项执行完后再返回 |
os_cancel_all_work | 取消系统工作队列上的所有未执行的工作项(包括正在排队的和延时执行的),正在执行的工作项不能取消 |
os_workqueue_create
该函数用于创建工作队列,内部会创建一个对应的任务,函数原型如下:
os_workqueue_t *os_workqueue_create(const char *name, os_uint32_t stack_size, os_uint8_t priority);
参数 | 说明 |
---|---|
name | 工作队列的名字 |
stack_size | 工作队列对应任务的栈大小 |
priority | 工作队列对应任务的优先级 |
返回 | 说明 |
非OS_NULL | 创建成功,返回工作队列句柄 |
OS_NULL | 创建失败 |
os_workqueue_destroy
该函数用于销毁工作队列,函数原型如下:
os_err_t os_workqueue_destroy(os_workqueue_t *queue);
参数 | 说明 |
---|---|
queue | 工作队列句柄 |
返回 | 说明 |
OS_EOK | 销毁成功 |
os_workqueue_submit_work
该函数用于向工作队列上提交工作项,可指定延时时间,函数原型如下:
os_err_t os_workqueue_submit_work(os_workqueue_t *queue, os_work_t *work, os_tick_t delay_time);
参数 | 说明 |
---|---|
queue | 工作队列句柄 |
work | 待提交的工作项,该工作项需提前用os_work_init()初始化 |
delay_time | 延时时间,可取值范围0~(OS_TICK_MAX / 2 - 1) |
返回 | 说明 |
OS_EOK | 提交成功 |
OS_EBUSY | 该工作项之前已被提交,但还未执行完成 |
os_workqueue_cancel_work
该函数用于取消工作队列上的指定工作项,若该工作项已开始执行,则返回OS_EBUSY,函数原型如下:
os_err_t os_workqueue_cancel_work(os_workqueue_t *queue, os_work_t *work);
参数 | 说明 |
---|---|
queue | 工作队列句柄 |
work | 待取消的工作项 |
返回 | 说明 |
OS_EOK | 取消成功 |
OS_EBUSY | 取消失败,该工作项正在执行 |
OS_ERROR | 其它错误 |
os_workqueue_cancel_work_sync
该函数用于以同步方式取消工作队列上的指定工作项,若该工作项已开始执行,则会等待其执行完成,函数原型如下:
os_err_t os_workqueue_cancel_work_sync(os_workqueue_t *queue, os_work_t *work);
参数 | 说明 |
---|---|
queue | 工作队列句柄 |
work | 待取消的工作项 |
返回 | 说明 |
OS_EOK | 取消成功 |
OS_ERROR | 取消错误 |
os_workqueue_cancel_all_work
该函数用于取消工作队列上的所有工作项(包括正在排队的和延时执行的),正在执行的工作项不能取消,函数原型如下:
void os_workqueue_cancel_all_work(os_workqueue_t *queue);
参数 | 说明 |
---|---|
queue | 工作队列句柄 |
返回 | 说明 |
无 | 无 |
os_work_init
该函数用于初始化工作项,函数原型如下:
void os_work_init(os_work_t *work, void (*func)(struct os_work *work, void *data), void *data);
参数 | 说明 |
---|---|
work | 工作项句柄,由使用者提供 |
func | 工作项函数 |
data | 工作项函数的参数 |
返回 | 说明 |
无 | 无 |
os_work_deinit
该函数用于反初始化工作项,可以指定清除函数,函数原型如下:
void os_work_deinit(os_work_t *work, void (*cleanup)(os_work_t *work));
参数 | 说明 |
---|---|
work | 工作项句柄 |
cleanup | 清除函数,使用者可以通过注册此函数,在反初始化工作项后执行一些清理的操作 |
返回 | 说明 |
无 | 无 |
os_submit_work
该函数向系统工作队列提交工作项(系统工作队列默认任务的栈为OS_SYSTEM_WORKQUEUE_STACK_SIZE,优先级为OS_SYSTEM_WORKQUEUE_PRIORITY),函数原型如下:
os_err_t os_submit_work(os_work_t *work, os_tick_t time);
参数 | 说明 |
---|---|
work | 向系统工作队列提交的工作项句柄,该工作项需提前使用os_work_init()初始化 |
time | 延时时间,可取值范围0~(OS_TICK_MAX / 2 - 1) |
返回 | 说明 |
OS_EOK | 提交成功 |
OS_EBUSY | 该工作项之前已被提交,但还未执行完成 |
os_cancel_work
该函数用于取消系统工作队列上指定的工作项,若该工作项已开始运行,则返回OS_EBUSY,函数原型如下:
os_err_t os_cancel_work(os_work_t *work);
参数 | 说明 |
---|---|
work | 待取消的工作项句柄 |
返回 | 说明 |
OS_EOK | 取消成功 |
OS_EBUSY | 取消失败,该工作项正在执行 |
OS_ERROR | 其它错误 |
os_cancel_work_sync
该函数用于以同步方式取消系统工作队列上的指定工作项,若该工作项已开始执行,则会等待其执行完成,函数原型如下:
os_err_t os_cancel_work_sync(os_work_t *work);
参数 | 说明 |
---|---|
work | 待取消的工作项句柄 |
返回 | 说明 |
OS_EOK | 取消成功 |
OS_ERROR | 取消错误 |
os_cancel_all_work
该函数用于取消系统工作队列上的所有工作项(包括正在排队的和延时执行的),正在执行的工作项不能取消,函数原型如下:
void os_cancel_all_work(void);
使用示例
自己创建工作队列使用示例
本例创建了自己的工作队列,然后在任务1中周期性的提交工作项到该工作队列,在任务2中分别提交了一个需要延时的工作项和不需要延时的工作项到该工作队列
#include <oneos_config.h>
#include <os_dbg.h>
#include <os_errno.h>
#include <os_task.h>
#include <shell.h>
#include <os_workqueue.h>
#define TEST_TAG "TEST"
#define TASK_STACK_SIZE 1024
#define TASK1_PRIORITY 15
#define TASK2_PRIORITY 16
#define TASK_WQ_PRIORITY 10
#define TASK_TIMESLICE 10
static os_workqueue_t *workqueue_test;
static os_work_t work1;
static os_work_t work2;
static os_work_t work3;
void work1_func(os_work_t *work, void *data)
{
LOG_W(TEST_TAG, "work1_func, data:%d", *(os_uint32_t *)data);
}
void work2_func(os_work_t *work, void *data)
{
LOG_W(TEST_TAG, "work2_func");
}
void work3_func(os_work_t *work, void *data)
{
LOG_W(TEST_TAG, "work3_func");
}
void task1_entry(void *para)
{
os_uint32_t data = 0;
os_work_init(&work1, work1_func, &data);
while(1)
{
data++;
LOG_W(TEST_TAG, "task1 submit work1");
while(OS_EBUSY == os_workqueue_submit_work(workqueue_test, &work1, 0))
{
os_task_sleep(10);
}
os_task_sleep(500);
}
}
void task2_entry(void *para)
{
os_tick_t delay_time = 1000;
os_work_init(&work2, work2_func, OS_NULL);
LOG_W(TEST_TAG, "task2 submit work2, delay_time:%d", delay_time);
if(OS_EOK != os_workqueue_submit_work(workqueue_test, &work2, delay_time))
{
LOG_W(TEST_TAG, "task2 submit work2 ERR");
}
os_task_sleep(500);
delay_time = 0;
os_work_init(&work3, work3_func, OS_NULL);
LOG_W(TEST_TAG, "task2 submit work3, delay_time:%d", delay_time);
if(OS_EOK != os_workqueue_submit_work(workqueue_test, &work3, delay_time))
{
LOG_W(TEST_TAG, "task2 submit work3 ERR");
}
}
void workqueue_sample(void)
{
os_task_t *task1 = OS_NULL;
os_task_t *task2 = OS_NULL;
workqueue_test = os_workqueue_create("workqueue", TASK_STACK_SIZE, TASK_WQ_PRIORITY);
if (!workqueue_test)
{
LOG_W(TEST_TAG, "workqueue_sample workqueue create ERR");
return;
}
task1 = os_task_create("task1",
task1_entry,
OS_NULL,
TASK_STACK_SIZE,
TASK1_PRIORITY,
TASK_TIMESLICE);
if (task1)
{
LOG_W(TEST_TAG, "workqueue_sample startup task1");
os_task_startup(task1);
}
task2 = os_task_create("task2",
task2_entry,
OS_NULL,
TASK_STACK_SIZE,
TASK2_PRIORITY,
TASK_TIMESLICE);
if (task2)
{
LOG_W(TEST_TAG, "workqueue_sample startup task2");
os_task_startup(task2);
}
}
SH_CMD_EXPORT(test_workqueue, workqueue_sample, "test workqueue");
运行结果如下:
sh />test_workqueue
W/TEST: workqueue_sample startup task1
W/TEST: task1 submit work1
W/TEST: work1_func, data:1
W/TEST: workqueue_sample startup task2
W/TEST: task2 submit work2, delay_time:1000
W/TEST: task1 submit work1
W/TEST: work1_func, data:2
W/TEST: task2 submit work3, delay_time:0
W/TEST: work3_func
W/TEST: task1 submit work1
W/TEST: work2_func
W/TEST: work1_func, data:3
W/TEST: task1 submit work1
W/TEST: work1_func, data:4
W/TEST: task1 submit work1
W/TEST: work1_func, data:5
系统工作队列使用示例
本例使用系统工作队列,不创建自己的工作队列,用另外一套接口,达到和上面示例中一样的效果,使用起来更简单方便
#include <oneos_config.h>
#include <os_dbg.h>
#include <os_errno.h>
#include <os_task.h>
#include <shell.h>
#include <os_workqueue.h>
#define TEST_TAG "TEST"
#define TASK_STACK_SIZE 1024
#define TASK1_PRIORITY 15
#define TASK2_PRIORITY 16
#define TASK_TIMESLICE 10
static os_work_t work1;
static os_work_t work2;
static os_work_t work3;
void work1_func(os_work_t *work, void *data)
{
LOG_W(TEST_TAG, "work1_func, data:%d", *(os_uint32_t *)data);
}
void work2_func(os_work_t *work, void *data)
{
LOG_W(TEST_TAG, "work2_func");
}
void work3_func(os_work_t *work, void *data)
{
LOG_W(TEST_TAG, "work3_func");
}
void task1_entry(void *para)
{
os_uint32_t data = 0;
os_work_init(&work1, work1_func, &data);
while(1)
{
data++;
LOG_W(TEST_TAG, "task1 submit work1");
while(OS_EBUSY == os_submit_work(&work1, 0))
{
os_task_sleep(10);
}
os_task_sleep(500);
}
}
void task2_entry(void *para)
{
os_tick_t delay_time = 1000;
os_work_init(&work2, work2_func, OS_NULL);
LOG_W(TEST_TAG, "task2 submit work2, delay_time:%d", delay_time);
if(OS_EOK != os_submit_work(&work2, delay_time))
{
LOG_W(TEST_TAG, "task2 submit work2 ERR");
}
os_task_sleep(500);
delay_time = 0;
os_work_init(&work3, work3_func, OS_NULL);
LOG_W(TEST_TAG, "task2 submit work3, delay_time:%d", delay_time);
if(OS_EOK != os_submit_work(&work3, delay_time))
{
LOG_W(TEST_TAG, "task2 submit work3 ERR");
}
}
void sys_workqueue_sample(void)
{
os_task_t *task1 = OS_NULL;
os_task_t *task2 = OS_NULL;
task1 = os_task_create("task1",
task1_entry,
OS_NULL,
TASK_STACK_SIZE,
TASK1_PRIORITY,
TASK_TIMESLICE);
if (task1)
{
LOG_W(TEST_TAG, "sys_workqueue_sample startup task1");
os_task_startup(task1);
}
task2 = os_task_create("task2",
task2_entry,
OS_NULL,
TASK_STACK_SIZE,
TASK2_PRIORITY,
TASK_TIMESLICE);
if (task2)
{
LOG_W(TEST_TAG, "sys_workqueue_sample startup task2");
os_task_startup(task2);
}
}
SH_CMD_EXPORT(test_sys_workqueue, sys_workqueue_sample, "test system workqueue");
运行结果如下:
sh />test_sys_workqueue
W/TEST: sys_workqueue_sample startup task1
W/TEST: task1 submit work1
W/TEST: work1_func, data:1
W/TEST: sys_workqueue_sample startup task2
W/TEST: task2 submit work2, delay_time:1000
W/TEST: task1 submit work1
W/TEST: work1_func, data:2
W/TEST: task2 submit work3, delay_time:0
W/TEST: work3_func
W/TEST: task1 submit work1
W/TEST: work2_func
W/TEST: work1_func, data:3
W/TEST: task1 submit work1
W/TEST: work1_func, data:4
W/TEST: task1 submit work1
W/TEST: work1_func, data:5