news 2026/1/6 10:05:15

Zephyr RTOS 工作队列函数(k_work_reschedule )的应用方法介绍

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Zephyr RTOS 工作队列函数(k_work_reschedule )的应用方法介绍

目录

概述

1 函数功能介绍

1.1 函数原型

1.2 k_work工作队列使用流程

1.3 其他相关函数

2 常用的示例

2.1 基本用法

2.2 动态分配延迟工作项

2.3 检查并重新安排

2.4 使用绝对时间

3 k_work_reschedule 的非阻塞特性

4 实现"异步等待"的模式

4.1 回调通知

4.2 状态机

4.3 性能注意事项

4.4 常见问题和解决方法


概述

k_work_reschedule函数在 Zephyr RTOS 中用于重新安排延迟工作项(delayed work)的执行时间。该函数在需要动态调整定时任务时非常有用,特别是在实现防抖、超时重试、周期性任务等场景。本文详细介绍其用法。

1 函数功能介绍

1.1 函数原型

k_work_reschedule函数原型如下:

int k_work_reschedule(struct k_work_delayable *dwork, k_timeout_t delay);

- 参数说明

参数类型描述
dworkstruct k_work_delayable *指向延迟工作项的指针
delayk_timeout_t新的延迟时间

返回值:

  • 0:成功重新安排

  • -EINVAL:无效参数

  • -EALREADY:工作项已在运行或已完成

1.2 k_work工作队列使用流程

step-1: 定义队列变量

static struct k_work_delayable demo_rec_timeout;

step-2: 定义callback函数

static void callback_timeout_handler(struct k_work *item) { // do something }

step-3: 执行回调函数

#define BLE_WAIT_TIME 300 #define BLE_WAIT_FOR_RECV_DELAY K_MSEC(BLE_WAIT_TIME) static void do_timeout_reschedule( void ) { k_work_reschedule(&demo_rec_timeout, BLE_WAIT_FOR_RECV_DELAY); }

step-4: 初始化k_work

void ble_rec_timeout_init( void ) { k_work_init_delayable(&demo_rec_timeout, demo_rec_timeout_handler); }

1.3 其他相关函数

函数描述是否取消之前的安排
k_work_schedule()首次安排延迟工作
k_work_reschedule()重新安排延迟工作
k_work_schedule_for_queue()安排到指定队列

2 常用的示例

2.1 基本用法

#include <zephyr/kernel.h> #include <zephyr/sys/work.h> // 定义工作处理函数 void my_work_handler(struct k_work *work) { printk("Work executed!\n"); } // 定义延迟工作项 K_WORK_DELAYABLE_DEFINE(my_dwork, my_work_handler); void main(void) { // 第一次安排:1秒后执行 k_work_reschedule(&my_dwork, K_SECONDS(1)); // 在1秒内重新安排:改为2秒后执行 k_work_reschedule(&my_dwork, K_SECONDS(2)); }

2.2 动态分配延迟工作项

struct k_work_delayable *dwork; void init_work(void) { // 动态分配延迟工作项 dwork = k_malloc(sizeof(struct k_work_delayable)); // 初始化 k_work_init_delayable(dwork, my_work_handler); // 安排工作 k_work_reschedule(dwork, K_MSEC(500)); }

2.3 检查并重新安排

void reschedule_if_needed(void) { // 检查工作项是否在等待队列中 if (k_work_delayable_is_pending(&my_dwork)) { // 取消之前的安排,重新设置 k_work_reschedule(&my_dwork, K_SECONDS(5)); } else { // 第一次安排 k_work_schedule(&my_dwork, K_SECONDS(5)); } }

2.4 使用绝对时间

// 安排到特定时间点执行 k_timepoint_t future_time = sys_timepoint_calc(K_SECONDS(10)); k_work_reschedule(&my_dwork, future_time);

3k_work_reschedule的非阻塞特性

1)立即返回

// 示例:调用立即返回,不等待工作项执行 int ret = k_work_reschedule(&my_dwork, K_SECONDS(1)); // 立即执行到这里,不阻塞 printk("立即返回,返回值: %d\n", ret);

2)从任何上下文调用

// 中断服务程序(ISR)中安全调用 void isr_handler(const void *arg) { // 中断上下文中调用 - 完全安全 k_work_reschedule(&irq_work, K_MSEC(10)); // 立即返回,不阻塞中断处理 }

3)不会等待工作项执行

void test_non_blocking(void) { printk("开始安排工作\n"); // 安排5秒后执行 k_work_reschedule(&delayed_work, K_SECONDS(5)); // 立即继续执行,不等待5秒 printk("安排完成,继续执行其他任务\n"); // 这里的工作会立即执行,而不是等待5秒 do_other_tasks(); }

与阻塞函数的对比:

1) 阻塞方式(不要在工作项中使用)

void blocking_work_handler(struct k_work *work) { // 错误示例:这会使工作队列线程阻塞 k_sleep(K_SECONDS(5)); // ❌ 阻塞! printk("5秒后...\n"); } // 主线程中调用 void main_task(void) { k_work_reschedule(&blocking_work, K_SECONDS(1)); // 虽然这里立即返回,但工作队列线程会被阻塞! }

2) 非阻塞方式(正确做法)

void non_blocking_work_handler(struct k_work *work) { // 立即执行耗时任务 do_intensive_processing(); // 或者分解任务 continue_processing_later(work); } // 如果需要延迟,使用重新安排 void continue_processing_later(struct k_work *work) { struct k_work_delayable *dwork = k_work_delayable_from_work(work); // 非阻塞地重新安排自己 k_work_reschedule(dwork, K_MSEC(100)); }

4 实现"异步等待"的模式

4.1 回调通知

struct async_context { struct k_work_delayable work; struct k_sem completion; void *result; }; void async_work_handler(struct k_work *work) { struct async_context *ctx = CONTAINER_OF(work, struct async_context, work.work); // 执行异步任务 ctx->result = perform_async_operation(); // 通知等待者 k_sem_give(&ctx->completion); } // 调用者 void caller_function(void) { struct async_context ctx; k_sem_init(&ctx.completion, 0, 1); k_work_init_delayable(&ctx.work, async_work_handler); // 启动异步工作 - 立即返回 k_work_reschedule(&ctx.work, K_NO_WAIT); // 可以做其他事情... do_other_work(); // 等待完成(如果需要) k_sem_take(&ctx.completion, K_FOREVER); }

4.2 状态机

enum work_state { STATE_IDLE, STATE_PROCESSING, STATE_COMPLETE }; struct stateful_work { struct k_work_delayable dwork; enum work_state state; int step; }; void state_machine_work_handler(struct k_work *work) { struct stateful_work *sw = CONTAINER_OF(k_work_delayable_from_work(work), struct stateful_work, dwork); switch (sw->step) { case 0: // 第一步 start_processing(); sw->step = 1; // 立即安排下一步 k_work_reschedule(&sw->dwork, K_NO_WAIT); break; case 1: // 第二步 continue_processing(); sw->step = 2; // 延迟执行下一步 k_work_reschedule(&sw->dwork, K_MSEC(50)); break; case 2: // 完成 finish_processing(); sw->state = STATE_COMPLETE; break; } }

4.3 性能注意事项

1) 优势

// 1. 不阻塞调用者 void high_priority_thread(void) { while (1) { // 处理实时任务... // 安排后台工作 - 不影响实时性 k_work_reschedule(&bg_work, K_NO_WAIT); // 继续执行,无延迟 } } // 2. 批量处理 void batch_processor(void) { for (int i = 0; i < 100; i++) { // 快速安排所有工作 k_work_reschedule(&work_items[i], K_NO_WAIT); // 立即继续 } }

2) 注意事项

// 注意:避免安排过快导致队列溢出 void rapid_fire_work(void) { for (int i = 0; i < 1000; i++) { // 可能使工作队列过载 k_work_reschedule(&work, K_NO_WAIT); } // 考虑使用工作合并或速率限制 } // 更好的做法:合并工作 struct batch_context { struct k_work_delayable work; int pending_count; int data[1000]; }; void batch_work_handler(struct k_work *work) { struct batch_context *ctx = CONTAINER_OF(work, struct batch_context, work.work); // 处理所有待处理数据 for (int i = 0; i < ctx->pending_count; i++) { process_data(ctx->data[i]); } ctx->pending_count = 0; } void schedule_batch_work(struct batch_context *ctx, int new_data) { ctx->data[ctx->pending_count++] = new_data; // 延迟安排,合并多次调用 if (ctx->pending_count == 1) { k_work_reschedule(&ctx->work, K_MSEC(10)); } }

4.4 常见问题和解决方法

1) 如何知道工作何时完成?

// 使用完成信号量 struct tracked_work { struct k_work_delayable dwork; struct k_sem done; bool completed; }; void tracked_work_handler(struct k_work *work) { struct tracked_work *tw = CONTAINER_OF(k_work_delayable_from_work(work), struct tracked_work, dwork); do_work(); tw->completed = true; k_sem_give(&tw->done); } // 等待完成(非阻塞检查) bool is_work_done(struct tracked_work *tw) { return tw->completed; } // 或阻塞等待 void wait_for_work(struct tracked_work *tw) { k_sem_take(&tw->done, K_FOREVER); }

2)如何取消安排的工作?

// 取消延迟工作 int cancel_work(struct k_work_delayable *dwork) { // 取消已安排但未执行的工作 int ret = k_work_cancel_delayable(dwork); if (ret == 0) { printk("工作取消成功\n"); } else if (ret == -EINPROGRESS) { printk("工作正在执行\n"); } return ret; }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/19 13:28:23

告别广告捆绑!360 压缩国际版:轻量纯净,2.3MB 装机即用

一、前言 作为每天和文件打交道的打工人&#xff0c;压缩软件早已是电脑必备工具&#xff0c;但选对一款却堪比 “抽盲盒”—— 有的功能强悍却藏着试用期陷阱&#xff0c;有的免费使用却被广告弹窗轰炸&#xff0c;就连知名的国产压缩工具也常因捆绑插件、频繁弹窗让用户怨声…

作者头像 李华
网站建设 2025/12/19 13:25:38

38、利用应答文件和Sysprep进行系统部署与磁盘克隆

利用应答文件和Sysprep进行系统部署与磁盘克隆 在系统部署过程中,我们常常需要使用各种工具和方法来确保配置的一致性和高效性。下面将详细介绍利用应答文件进行部署的相关内容,以及磁盘克隆的具体步骤。 安装注册表设置的工具和命令 在安装注册表设置时,我们可以使用以下…

作者头像 李华
网站建设 2025/12/19 13:25:37

FaceFusion在虚拟演唱会中的角色扮演应用

FaceFusion在虚拟演唱会中的角色扮演应用 如今&#xff0c;一场演唱会不再受限于舞台的物理边界。当邓丽君的面容随着周杰伦的歌声轻轻启唇&#xff0c;当粉丝上传一张自拍就能“站上”跨年晚会的C位&#xff0c;我们早已进入一个由AI驱动的娱乐新纪元。在这背后&#xff0c; …

作者头像 李华
网站建设 2025/12/26 19:09:12

40、利用Sysprep克隆磁盘与配置Windows PE全解析

利用Sysprep克隆磁盘与配置Windows PE全解析 在企业级的Windows系统部署过程中,磁盘克隆和系统预安装环境的配置是至关重要的环节。Sysprep工具和Windows PE环境在其中发挥着关键作用,下面将详细介绍它们的使用方法和相关技术要点。 利用Sysprep减少镜像数量 在管理磁盘镜…

作者头像 李华
网站建设 2025/12/20 19:26:54

53、Windows系统注册表设置全解析

Windows系统注册表设置全解析 在Windows系统中,注册表是一个非常重要的数据库,它存储了系统和应用程序的各种设置信息。下面将详细介绍一些常见的注册表设置及其操作方法。 1. Internet Explorer搜索URL设置 搜索URL是使用不同互联网搜索引擎的便捷方式。例如,可以创建一…

作者头像 李华
网站建设 2025/12/24 5:46:39

独家揭秘!这家电动雨棚设计安装公司凭啥脱颖而出?

独家揭秘&#xff01;这家电动雨棚设计安装公司凭啥脱颖而出&#xff1f;在电动雨棚市场竞争日益激烈的当下&#xff0c;有一家公司——洛阳杰昇电动推拉雨棚&#xff0c;却能在众多企业中脱颖而出&#xff0c;它究竟有何独特之处呢&#xff1f;下面为您详细揭秘。创新设计理念…

作者头像 李华