4. 互斥锁保护共享资源
任务说明
本案例在STM32F103开发板上,使用RT-Thread Nano实时操作系统创建两个LED闪烁任务。任务1采用忙等待延时(空循环占用CPU),任务2采用阻塞延时(调用系统延时函数主动释放CPU)。通过观察两个LED的闪烁行为以及空闲线程的运行情况,直观对比两种延时方式对CPU资源占用的差异。
原理简述
忙等待延时通过空循环消耗CPU时间,延时期间任务一直占用处理器,导致低优先级任务或空闲线程无法运行。阻塞延时则调用rt_thread_delay(),将当前任务挂起并触发线程调度,CPU转去执行其他就绪任务或空闲线程,延时结束后任务自动恢复就绪。两种方式都能实现周期性执行,但对系统实时性和CPU利用率的影响截然不同。
硬件连接
代码实现
创建文件main.c,完整代码如下:
#include "board.h"
#include "rtthread.h"
#define THREAD_PRIORITY1 8
#define THREAD_PRIORITY2 9
#define THREAD_STACK_SIZE 512
/* 忙等待延时函数(空循环) */
static void delay_busy(volatile uint32_t count)
{
while (count-- > 0) {
__NOP();
}
}
/* 任务1:忙等待延时,LED1每500ms翻转一次 */
static void thread1_entry(void *param)
{
rt_uint32_t i;
while (1) {
rt_pin_write(PA1, PIN_HIGH);
/* 忙等待约500ms(72MHz下粗略估算) */
for (i = 0; i < 36; i++) {
delay_busy(100000);
}
rt_pin_write(PA1, PIN_LOW);
for (i = 0; i < 36; i++) {
delay_busy(100000);
}
}
}
/* 任务2:阻塞延时,LED2每500ms翻转一次 */
static void thread2_entry(void *param)
{
while (1) {
rt_pin_write(PA2, PIN_HIGH);
rt_thread_delay(rt_tick_from_millisecond(500)); /* 阻塞延时500ms */
rt_pin_write(PA2, PIN_LOW);
rt_thread_delay(rt_tick_from_millisecond(500));
}
}
int main(void)
{
rt_thread_t thread1, thread2;
/* 配置LED引脚为输出 */
rt_pin_mode(PA1, PIN_MODE_OUTPUT);
rt_pin_mode(PA2, PIN_MODE_OUTPUT);
/* 创建任务1(忙等待) */
thread1 = rt_thread_create("busy",
thread1_entry,
RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY1,
10);
if (thread1 != RT_NULL) {
rt_thread_startup(thread1);
}
/* 创建任务2(阻塞延时) */
thread2 = rt_thread_create("block",
thread2_entry,
RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY2,
10);
if (thread2 != RT_NULL) {
rt_thread_startup(thread2);
}
return 0;
}
关键说明
- 任务1优先级为8,任务2优先级为9(数值越小优先级越高)。任务1使用忙等待时始终占用CPU,任务2即使优先级较低也无法运行,LED2不闪烁。
- 任务1的忙等待循环通过粗略估算实现约500ms延时,实际时间受编译器优化和系统时钟影响,不精确。
- 任务2调用
rt_thread_delay()主动挂起,调度器切换到空闲线程或其他就绪任务,LED2能够正常闪烁。 - 若将任务1的优先级调低(如改为10),则任务2的阻塞延时期间,任务1的忙等待会抢占CPU,导致LED2闪烁周期被拉长,进一步体现忙等待对系统调度的干扰。
编译与运行
- 使用Keil MDK或GCC工具链编译工程,下载到STM32F103开发板。
- 打开串口调试助手(波特率115200),连接开发板USART1。
验证方法
观察现象:
- 若LED1和LED2均以约1Hz频率交替闪烁(亮500ms灭500ms),说明两个任务都在正常运行。
- 若LED2不闪烁或闪烁极慢,而LED1正常闪烁,说明任务1的忙等待占用了几乎全部CPU时间,导致低优先级任务2无法获得调度。
判定标准:当任务1优先级高于任务2时,LED2应几乎不闪烁(忙等待独占CPU);将任务1优先级改为低于任务2后重新编译运行,LED2恢复约1Hz闪烁,证明阻塞延时能正确释放CPU。通过此对比即可验证忙等待与阻塞延时的本质区别。