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

目录

概述

[1 函数功能介绍](#1 函数功能介绍)

[1.1 函数原型](#1.1 函数原型)

[1.2 k_work工作队列使用流程](#1.2 k_work工作队列使用流程)

[1.3 其他相关函数](#1.3 其他相关函数)

[2 常用的示例](#2 常用的示例)

[2.1 基本用法](#2.1 基本用法)

[2.2 动态分配延迟工作项](#2.2 动态分配延迟工作项)

[2.3 检查并重新安排](#2.3 检查并重新安排)

[2.4 使用绝对时间](#2.4 使用绝对时间)

[3 k_work_reschedule 的非阻塞特性](#3 k_work_reschedule 的非阻塞特性)

[4 实现"异步等待"的模式](#4 实现"异步等待"的模式)

[4.1 回调通知](#4.1 回调通知)

[4.2 状态机](#4.2 状态机)

[4.3 性能注意事项](#4.3 性能注意事项)

[4.4 常见问题和解决方法](#4.4 常见问题和解决方法)


概述

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

1 函数功能介绍

1.1 函数原型

k_work_reschedule 函数原型如下:

cpp 复制代码
int k_work_reschedule(struct k_work_delayable *dwork, k_timeout_t delay);
  • 参数说明
参数 类型 描述
dwork struct k_work_delayable * 指向延迟工作项的指针
delay k_timeout_t 新的延迟时间

返回值:

  • 0:成功重新安排

  • -EINVAL:无效参数

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

1.2 k_work工作队列使用流程

step-1: 定义队列变量

cpp 复制代码
static struct k_work_delayable demo_rec_timeout;

step-2: 定义callback函数

cpp 复制代码
static void callback_timeout_handler(struct k_work *item)
{
   // do something 

}

step-3: 执行回调函数

cpp 复制代码
#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

cpp 复制代码
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 基本用法

cpp 复制代码
#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 动态分配延迟工作项

cpp 复制代码
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 检查并重新安排

cpp 复制代码
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 使用绝对时间

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

3 k_work_reschedule 的非阻塞特性

1) 立即返回

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

2) 从任何上下文调用

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

3) 不会等待工作项执行

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

与阻塞函数的对比:

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

cpp 复制代码
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) 非阻塞方式(正确做法)

cpp 复制代码
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 回调通知

cpp 复制代码
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 状态机

cpp 复制代码
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) 优势

cpp 复制代码
// 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) 注意事项

cpp 复制代码
// 注意:避免安排过快导致队列溢出
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) 如何知道工作何时完成?

cpp 复制代码
// 使用完成信号量
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)如何取消安排的工作?

cpp 复制代码
// 取消延迟工作
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;
}
相关推荐
Strugglingler8 天前
Zephyr 的 Counter alarm
alarm·counter·zephyr
Amonter17 天前
Zephyr OS驱动0.96OLED
oled·ssd1306·zephyr
Amonter19 天前
Ubuntu下搭建zephyrOS开发环境
rtos·zephyr·esp32c3
驱动探索者1 个月前
Zephyr 获取 cpu 占用率异常bug分析
bug·rtos·zephyr
jz-炸芯片的zero2 个月前
【Zephyr存储专题】16_内存泄露检测可视化脚本自动化
自动化·嵌入式·ai编程·zephyr
jz-炸芯片的zero2 个月前
【Zephyr电源与功耗专题】15_功耗优化测试工具与手段
嵌入式·zephyr·功耗
jz-炸芯片的zero3 个月前
【Zephyr电源与功耗专题】14_BMS电池管理算法(三重验证机制实现高精度电量估算)
单片机·物联网·算法·zephyr·bms电源管理算法
jz-炸芯片的zero4 个月前
【Zephyr炸裂知识系列】11_手撸内存泄露监测算法
驱动开发·算法·iot·rtos·内存泄露·zephyr
mftang4 个月前
Zephyr 中的 bt_le_per_adv_set_data 函数的介绍和应用方法
嵌入式硬件·nordic·zephyr