2. 多线程并发执行

任务目标

在ThreadX中创建3个不同优先级的线程,每个线程循环打印自身标识与执行次数,通过观察输出顺序理解基于优先级的抢占式调度机制。本案例使用ThreadX的CMSIS-API封装(tx_thread_create),在STM32裸机环境中运行。

核心实现

#include "tx_api.h"
#include <stdio.h>

/* 线程控制块与栈 */
TX_THREAD thread_low, thread_mid, thread_high;
uint8_t stack_low[512], stack_mid[512], stack_high[512];

/* 共享计数器 */
volatile uint32_t counter = 0;

/* 线程入口函数 */
void thread_entry(ULONG id) {
    while (1) {
        counter++;
        printf("Thread %lu | count=%lu\r\n", id, counter);
        tx_thread_sleep(10);  /* 主动让出CPU,10个tick */
    }
}

void app_main(void) {
    /* 初始化ThreadX内核 */
    tx_kernel_enter();
}

void tx_application_define(void *first_unused_memory) {
    (void)first_unused_memory;

    /* 创建3个线程:优先级数值越小优先级越高 */
    tx_thread_create(&thread_high, "HIGH", thread_entry, 1,
                     stack_high, sizeof(stack_high),
                     5, 5, TX_NO_TIME_SLICE, TX_AUTO_START);

    tx_thread_create(&thread_mid, "MID", thread_entry, 2,
                     stack_mid, sizeof(stack_mid),
                     10, 10, TX_NO_TIME_SLICE, TX_AUTO_START);

    tx_thread_create(&thread_low, "LOW", thread_entry, 3,
                     stack_low, sizeof(stack_low),
                     15, 15, TX_NO_TIME_SLICE, TX_AUTO_START);
}

运行与观察

环境依赖:STM32F4(或任意Cortex-M)开发板,集成ThreadX库(含CMSIS-API),串口重定向至printf。

编译与烧录:使用Keil MDK或STM32CubeIDE,将上述代码加入工程,确保tx_api.h头文件路径正确。编译后通过ST-Link烧录。

验证方法:

  1. 打开串口助手(115200-8-N-1),复位开发板。
  2. 观察输出:由于高优先级线程(ID=1)最先运行,且每次tx_thread_sleep(10)后重新被调度,输出顺序应呈现为1, 2, 3, 1, 2, 3...的循环(每个线程各打印一次后,高优先级再次抢占)。
  3. 判定通过条件:串口持续输出三个线程的交替打印,且count值单调递增,无线程饿死(低优先级线程ID=3至少每轮能执行一次)。

调度机制说明

ThreadX采用优先级抢占式调度:高优先级线程就绪时立即抢占低优先级线程。本案例中三个线程均以TX_AUTO_START创建,初始就绪顺序为优先级从高到低。每个线程执行一次打印后调用tx_thread_sleep进入挂起状态,使同优先级或低优先级线程获得执行机会。由于三个线程优先级不同且无时间片轮转(TX_NO_TIME_SLICE),调度顺序完全由优先级决定。

预期输出示例

Thread 1 | count=1
Thread 2 | count=2
Thread 3 | count=3
Thread 1 | count=4
Thread 2 | count=5
Thread 3 | count=6
...

以上为基于代码逻辑的确定性输出:高优先级线程先运行,随后中、低优先级依次执行,形成固定轮转顺序。