3. 线程优先级抢占
任务目标
创建两个不同优先级的线程,通过共享变量和串口日志展示高优先级线程抢占低优先级线程的执行过程。低优先级线程执行较慢任务时,高优先级线程就绪后立即抢占CPU。
核心实现
#include "tx_api.h"
#include <stdio.h>
/* 共享变量用于观察执行顺序 */
volatile unsigned int low_thread_count = 0;
volatile unsigned int high_thread_count = 0;
volatile unsigned int preemption_flag = 0;
/* 线程控制块与栈 */
TX_THREAD low_thread;
TX_THREAD high_thread;
static unsigned char low_stack[1024];
static unsigned char high_stack[1024];
/* 低优先级线程:模拟耗时操作 */
void low_priority_entry(ULONG arg)
{
(void)arg;
while(1)
{
low_thread_count++;
/* 模拟耗时循环,给高优先级线程抢占机会 */
for(volatile int i = 0; i < 200000; i++);
/* 若高优先级线程已运行,则记录抢占发生 */
if(high_thread_count > 0)
{
preemption_flag = 1;
}
tx_thread_sleep(10); /* 主动让出CPU */
}
}
/* 高优先级线程:短促执行 */
void high_priority_entry(ULONG arg)
{
(void)arg;
while(1)
{
high_thread_count++;
tx_thread_sleep(50); /* 休眠较长时间,让低优先级线程运行 */
}
}
/* 应用程序入口 */
void tx_application_define(void *first_unused_memory)
{
(void)first_unused_memory;
/* 创建低优先级线程(优先级25) */
tx_thread_create(&low_thread, "Low", low_priority_entry, 0,
low_stack, sizeof(low_stack),
25, 25, TX_NO_TIME_SLICE, TX_AUTO_START);
/* 创建高优先级线程(优先级5) */
tx_thread_create(&high_thread, "High", high_priority_entry, 0,
high_stack, sizeof(high_stack),
5, 5, TX_NO_TIME_SLICE, TX_AUTO_START);
}
运行与验证
编译环境:ThreadX库已链接,包含 tx_api.h。使用任意支持ThreadX的ARM/RISC-V工具链编译,入口函数为 tx_application_define。
验证方法:在调试器中观察以下变量:
low_thread_count:低优先级线程执行次数high_thread_count:高优先级线程执行次数preemption_flag:当高优先级线程运行后,低优先级线程再次获得CPU时置1
通过条件:
- 程序正常运行,两个线程均持续执行,计数递增。
preemption_flag在运行后变为1,证明高优先级线程在低优先级线程耗时循环期间抢占执行。- 高优先级线程计数增长速度低于低优先级线程(因高优先级休眠50tick,低优先级休眠10tick),但高优先级一旦就绪即可打断低优先级。
预期行为说明:低优先级线程在耗时循环中(约200000次空循环)被高优先级线程抢占,高优先级线程执行完休眠后,低优先级线程从断点继续执行。通过调试器暂停观察,可看到两个计数交替增长,且高优先级线程每次运行都会打断低优先级线程的耗时循环。
关键机制
ThreadX使用基于优先级的抢占式调度:高优先级线程(数值小)就绪时立即获得CPU,无需等待当前线程主动让出。本案例中低优先级线程的耗时循环模拟了不可中断的计算过程,高优先级线程的唤醒(休眠结束)会触发调度器抢占,验证了优先级抢占的核心行为。