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");
}
构建与运行
- 在项目目录下创建
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)
- 使用 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 为抢占式),此处不影响功能,仅作演示。