4. 线程休眠与唤醒

任务目标

本案例演示 Zephyr RTOS 中线程的休眠与唤醒机制。创建一个工作线程,该线程循环执行:打印当前 tick 值 → 调用 k_sleep() 休眠 1 秒 → 唤醒后继续打印并重复。主线程(main)仅负责启动工作线程后退出。通过串口日志观察线程在休眠前后的执行时序,验证 k_sleep 让出 CPU 并在指定时间后恢复执行的行为。

环境与依赖

  • Zephyr RTOS 3.x 或更高版本
  • 开发板:任意支持串口输出的板卡(如 qemu_x86、nrf52840dk_nrf52840)
  • 依赖:CONFIG_SERIAL(串口输出)、CONFIG_PRINTK(日志打印)

完整实现

在项目根目录创建 prj.conf 与 src/main.c,内容如下:

# prj.conf
CONFIG_SERIAL=y
CONFIG_PRINTK=y
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=1000000
/* src/main.c */
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>

/* 工作线程栈与线程控制块 */
#define STACK_SIZE 1024
#define THREAD_PRIORITY 7

K_THREAD_STACK_DEFINE(worker_stack, STACK_SIZE);
static struct k_thread worker_thread_data;

/* 工作线程入口函数 */
static void worker_entry(void *arg1, void *arg2, void *arg3)
{
    ARG_UNUSED(arg1);
    ARG_UNUSED(arg2);
    ARG_UNUSED(arg3);

    while (1) {
        /* 打印休眠前的当前 tick */
        printk("Worker: about to sleep, tick=%lld\n", k_uptime_get());

        /* 休眠 1000ms(1秒) */
        k_sleep(K_MSEC(1000));

        /* 唤醒后打印当前 tick */
        printk("Worker: woke up, tick=%lld\n", k_uptime_get());
    }
}

void main(void)
{
    printk("Main: starting worker thread\n");

    /* 创建并启动工作线程 */
    k_thread_create(&worker_thread_data, worker_stack,
                    STACK_SIZE, worker_entry,
                    NULL, NULL, NULL,
                    THREAD_PRIORITY, 0, K_NO_WAIT);

    /* 主线程退出,工作线程继续运行 */
    printk("Main: exiting, worker runs independently\n");
}

构建与运行

  1. 在项目目录下创建 CMakeLists.txt(标准 Zephyr 工程结构):
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(thread_sleep_demo)
target_sources(app PRIVATE src/main.c)
  1. 使用 west 构建并运行(以 qemu_x86 为例):
west build -b qemu_x86 .
west build -t run

验证方法与判定标准

运行后,在串口终端观察输出。预期输出模式如下(tick 数值随实际运行时间变化):

Main: starting worker thread
Main: exiting, worker runs independently
Worker: about to sleep, tick=0
Worker: woke up, tick=1000
Worker: about to sleep, tick=1000
Worker: woke up, tick=2000
Worker: about to sleep, tick=2000
...

通过条件:

  • “about to sleep”与“woke up”交替出现,且相邻两次打印的 tick 差值约为 1000(即 1 秒)。
  • “woke up”与下一次“about to sleep”的 tick 值相同(无额外延迟)。
  • 主线程打印退出信息后不再输出,工作线程持续运行。

若 tick 差值明显大于 1000,说明系统 tick 配置或休眠精度有问题;若线程未周期性打印,则检查线程优先级或栈大小配置。

关键说明

  • k_sleep() 使当前线程进入休眠状态,并让出 CPU 给其他就绪线程;休眠结束后线程自动回到就绪队列继续执行。
  • k_uptime_get() 返回系统启动以来的毫秒数,用于验证休眠时长。
  • 线程优先级 7 为协作式优先级(低于 0 为抢占式),此处不影响功能,仅作演示。