4. 创建并启动内核线程

任务目标

在Zephyr RTOS中创建两个不同优先级的内核线程,分别执行独立的任务函数,通过串口日志观察调度器按优先级抢占执行的行为。本案例使用k_thread_create完成线程创建,并显式设置线程优先级与栈大小。

环境准备

本案例基于native_posix开发板运行,无需真实硬件。确保Zephyr SDK已安装,并已导出ZEPHYR_BASE环境变量。项目依赖仅需Zephyr内核自身,无需额外模块。

完整实现

创建项目目录thread_demo,包含prj.conf与src/main.c两个文件。

prj.conf(启用内核对象名称,便于调试):

CONFIG_THREAD_NAME=y

src/main.c:


#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>

/* 线程栈定义:低优先级线程栈较大,高优先级线程栈较小 */
#define LOW_PRIO_STACK_SIZE 1024
#define HIGH_PRIO_STACK_SIZE 512

K_THREAD_STACK_DEFINE(low_prio_stack, LOW_PRIO_STACK_SIZE);
K_THREAD_STACK_DEFINE(high_prio_stack, HIGH_PRIO_STACK_SIZE);

/* 线程控制块 */
static struct k_thread low_prio_thread;
static struct k_thread high_prio_thread;

/* 低优先级线程入口:循环打印并主动让出CPU */
static void low_prio_entry(void *arg1, void *arg2, void *arg3)
{
    ARG_UNUSED(arg1);
    ARG_UNUSED(arg2);
    ARG_UNUSED(arg3);

    while (1) {
        printk("[Low ] Running (priority %d)\n",
               k_thread_priority_get(k_current_get()));
        /* 主动让出CPU,给高优先级线程运行机会 */
        k_yield();
    }
}

/* 高优先级线程入口:循环打印,无需让出CPU */
static void high_prio_entry(void *arg1, void *arg2, void *arg3)
{
    ARG_UNUSED(arg1);
    ARG_UNUSED(arg2);
    ARG_UNUSED(arg3);

    while (1) {
        printk("[High] Running (priority %d)\n",
               k_thread_priority_get(k_current_get()));
    }
}

void main(void)
{
    /* 创建低优先级线程:优先级7(数值越小优先级越高) */
    k_thread_create(&low_prio_thread, low_prio_stack,
                    LOW_PRIO_STACK_SIZE,
                    low_prio_entry, NULL, NULL, NULL,
                    7, 0, K_NO_WAIT);

    /* 创建高优先级线程:优先级2 */
    k_thread_create(&high_prio_thread, high_prio_stack,
                    HIGH_PRIO_STACK_SIZE,
                    high_prio_entry, NULL, NULL, NULL,
                    2, 0, K_NO_WAIT);

    /* 设置线程名称便于调试 */
    k_thread_name_set(&low_prio_thread, "low_prio");
    k_thread_name_set(&high_prio_thread, "high_prio");

    /* 主线程退出,调度器开始运行两个子线程 */
    printk("Main thread created two threads, exiting.\n");
}

构建与运行


cd thread_demo
west build -b native_posix
west build -t run

程序启动后,串口终端将持续输出日志。按Ctrl+C终止运行。

验证方法与判定标准

观察终端输出,满足以下条件即判定案例通过:

  • 首先出现Main thread created two threads, exiting.,随后调度器启动线程调度。
  • 输出中[High]日志连续出现多次,[Low]日志仅在[High]线程调用k_yield()让出CPU后才会出现(即[High]与[Low]交替打印,但[High]出现的频率明显更高)。
  • 日志中打印的优先级数值与创建时设置一致:低优先级线程打印priority 7,高优先级线程打印priority 2。

该现象说明:Zephyr调度器始终优先运行优先级数值更小的线程;高优先级线程就绪时抢占低优先级线程,低优先级线程仅在k_yield()主动让出CPU时获得运行机会。

常见问题

  • 只看到High日志,没有Low日志:高优先级线程为无限循环且不主动让出CPU,低优先级线程永远无法运行。这是预期行为,验证时需确认k_yield()确实在低优先级线程中生效。
  • 栈大小不足导致崩溃:若修改线程入口函数增加局部变量,需相应增大K_THREAD_STACK_DEFINE中的栈尺寸。当前512字节栈仅适用于简单打印任务。