3. 优先级抢占
任务目标
在ThreadX中创建两个不同优先级的线程,通过共享变量和延时操作,直观验证高优先级线程能够抢占正在运行的低优先级线程。本案例使用QEMU模拟的ARM Cortex-M3平台,无需真实硬件即可运行。
环境依赖
- ThreadX内核源码(本案例使用6.x版本)
- ARM GCC交叉编译器(arm-none-eabi-gcc)
- QEMU系统模拟器(qemu-system-arm)
核心实现
/* main.c - ThreadX优先级抢占演示 */
#include "tx_api.h"
/* 线程控制块与栈 */
TX_THREAD high_priority_thread;
TX_THREAD low_priority_thread;
static uint8_t high_stack[1024];
static uint8_t low_stack[1024];
/* 共享变量:记录当前运行线程ID */
volatile uint32_t current_thread_id = 0;
/* 抢占计数器:记录高优先级线程抢占次数 */
volatile uint32_t preemption_count = 0;
/* 高优先级线程(优先级5) */
void high_priority_entry(ULONG arg)
{
(void)arg;
while (1)
{
/* 记录当前运行线程 */
current_thread_id = 1;
/* 模拟短暂工作后主动让出CPU */
tx_thread_sleep(10);
/* 如果低优先级线程正在运行,说明发生了抢占 */
if (current_thread_id == 2)
{
preemption_count++;
}
}
}
/* 低优先级线程(优先级15) */
void low_priority_entry(ULONG arg)
{
(void)arg;
while (1)
{
/* 记录当前运行线程 */
current_thread_id = 2;
/* 长时间运行,不主动让出CPU */
volatile uint32_t delay = 0;
for (delay = 0; delay < 200000; delay++);
/* 如果高优先级线程在此期间运行过,则抢占已发生 */
if (current_thread_id == 1)
{
preemption_count++;
}
}
}
/* 应用程序初始化 */
void tx_application_define(void *first_unused_memory)
{
(void)first_unused_memory;
/* 创建高优先级线程 */
tx_thread_create(&high_priority_thread, "High",
high_priority_entry, 0,
high_stack, sizeof(high_stack),
5, 5, TX_NO_TIME_SLICE, TX_AUTO_START);
/* 创建低优先级线程 */
tx_thread_create(&low_priority_thread, "Low",
low_priority_entry, 0,
low_stack, sizeof(low_stack),
15, 15, TX_NO_TIME_SLICE, TX_AUTO_START);
}
编译与运行
# 编译(假设ThreadX源码位于./threadx)
arm-none-eabi-gcc -c -I./threadx/common/inc -I./threadx/ports/cortex_m3/gnu/inc \
main.c -o main.o
arm-none-eabi-gcc -c ./threadx/common/src/*.c ./threadx/ports/cortex_m3/gnu/src/*.c
arm-none-eabi-gcc -T ./threadx/ports/cortex_m3/gnu/example/build/linker.ld \
*.o -o tx_demo.elf -nostdlib -lgcc
# 运行(QEMU模拟Cortex-M3)
qemu-system-arm -machine lm3s6965evb -kernel tx_demo.elf -nographic
验证方法
在QEMU运行环境中,通过以下方式验证抢占行为:
- 在
high_priority_entry和low_priority_entry中分别设置断点,观察执行顺序:低优先级线程开始运行后,高优先级线程就绪时会立即打断低优先级线程。 - 检查
preemption_count变量:由于高优先级线程每次唤醒后都会检查低优先级线程是否在运行,该计数器会持续增长,证明抢占反复发生。 - 观察
current_thread_id的变化:该变量会频繁在1和2之间切换,且切换方向总是从2(低优先级)变为1(高优先级),说明高优先级线程主动抢占。
通过条件:程序正常运行不崩溃,preemption_count值持续递增,且current_thread_id从2变为1的次数与preemption_count一致。
关键说明
- 高优先级线程使用
tx_thread_sleep(10)主动让出CPU,使低优先级线程有机会运行;低优先级线程通过忙等待占用CPU,不主动让出。 - 当高优先级线程从睡眠中唤醒时,ThreadX调度器会立即暂停低优先级线程,切换到高优先级线程——这就是优先级抢占的核心机制。
- 两个线程共享
current_thread_id变量,用于标记当前持有CPU的线程,从而在代码层面确认抢占行为确实发生。