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烧录。
验证方法:
- 打开串口助手(115200-8-N-1),复位开发板。
- 观察输出:由于高优先级线程(ID=1)最先运行,且每次
tx_thread_sleep(10)后重新被调度,输出顺序应呈现为1, 2, 3, 1, 2, 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
...
以上为基于代码逻辑的确定性输出:高优先级线程先运行,随后中、低优先级依次执行,形成固定轮转顺序。