最近在学习RT-Thread的相关知识,记录一下心得。
优先级翻转
是指当一个高优先级线程试图通过信号量机制访问共享资源时,如果该信号量已被低优先级线程持有,而这个低优先级线程在运行过程中可能又被其他一些中等优先级的线程抢占,从而造成高优先级线程被许多具有较低优先级的线程阻塞,实时性得到难以保证。
一句话来讲:高优先级线程等待资源的过程中,被其他较低优先级的线程抢占了,造成了低优先级线程“抢占”高优先级线程的现象。
引入互斥量
互斥量能够防止线程优先级翻转,方式如下:
通过使用互斥量,低优先级的C会和高优先级的A同等优先级,就不会被其他低于A但是高于原先C的中等优先级抢占。
引入代码
说明:代码来自官方
#include <rtthread.h>
/* 指向线程控制块的指针 */
static rt_thread_t tid1 = RT_NULL;
static rt_thread_t tid2 = RT_NULL;
static rt_thread_t tid3 = RT_NULL;
static rt_mutex_t mutex = RT_NULL;
#define THREAD_PRIORITY 10
#define THREAD_STACK_SIZE 512
#define THREAD_TIMESLICE 5
/* 线程 1 入口 */
static void thread1_entry(void *parameter)
{
rt_kprintf("thread1_entry: the priority of thread1 is: %d\n", tid1->current_priority);
/* 先让低优先级线程运行 */
rt_thread_mdelay(100);
/* 此时 thread3 持有 mutex,并且 thread2 等待持有 mutex */
/* 检查 rt_kprintf("the producer generates a number: %d\n", array[set%MAXSEM]); 与 thread3 的优先级情况 */
if (tid2->current_priority != tid3->current_priority)
{
/* 优先级不相同,测试失败 */
rt_kprintf("thread1_entry: the priority of thread2 is: %d\n", tid2->current_priority);
rt_kprintf("thread1_entry: the priority of thread3 is: %d\n", tid3->current_priority);
rt_kprintf("thread1_entry: test failed.\n");
return;
}
else
{
rt_kprintf("thread1_entry: the priority of thread2 is: %d\n", tid2->current_priority);
rt_kprintf("thread1_entry: the priority of thread3 is: %d\n", tid3->current_priority);
rt_kprintf("thread1_entry: test OK.\n");
}
}
/* 线程 2 入口 */
static void thread2_entry(void *parameter)
{
rt_err_t result;
rt_kprintf("thread2_entry: the priority of thread2 is: %d\n", tid2->current_priority);
/* 先让低优先级线程运行 */
rt_thread_mdelay(50);
/*
* 试图持有互斥锁,此时 thread3 持有,应把 thread3 的优先级提升
* 到 thread2 相同的优先级
*/
result = rt_mutex_take(mutex, RT_WAITING_FOREVER);
if (result == RT_EOK)
{
/* 释放互斥锁 */
rt_mutex_release(mutex);
}
}
/* 线程 3 入口 */
static void thread3_entry(void *parameter)
{
rt_tick_t tick;
rt_err_t result;
rt_kprintf("thread3_entry: the priority of thread3 is: %d\n", tid3->current_priority);
result = rt_mutex_take(mutex, RT_WAITING_FOREVER);
if (result != RT_EOK)
{
rt_kprintf("thread3_entry: thread3 take a mutex, failed.\n");
}
/* 做一个长时间的循环,500ms */
tick = rt_tick_get();
while (rt_tick_get() - tick < (RT_TICK_PER_SECOND / 2)) ;
rt_mutex_release(mutex);
}
int pri_inversion(void)
{
/* 创建互斥锁 */
mutex = rt_mutex_create("mutex", RT_IPC_FLAG_FIFO);
if (mutex == RT_NULL)
{
rt_kprintf("create dynamic mutex failed.\n");
return -1;
}
/* 创建线程 1 高优先级 */
tid1 = rt_thread_create("thread1",
thread1_entry,
RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY - 1, //优先级是9
THREAD_TIMESLICE);
if (tid1 != RT_NULL)
rt_thread_startup(tid1);
/* 创建线程 2 中优先级 */
tid2 = rt_thread_create("thread2",
thread2_entry,
RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY, //优先级是10
THREAD_TIMESLICE);
if (tid2 != RT_NULL)
rt_thread_startup(tid2);
/* 创建线程 3 低优先级 */
tid3 = rt_thread_create("thread3",
thread3_entry,
RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY + 1, //优先级是11
THREAD_TIMESLICE);
if (tid3 != RT_NULL)
rt_thread_startup(tid3);
return 0;
}
简单分析
执行流程
- 先创建三个线程
- 先根据优先级输出每一个线程入口函数的第一句代码
- 由于延时函数的存在,低优先级线程(3)先运行,得到互斥量,因为500s循环的存在,线程3不会结束
- 中优先级线程(2)阻塞结束,比低优先级高,得到运行,也试图持有互斥量,此时会将线程3的优先级提高
- 此时,线程1也阻塞结束,优先级最高,得到运行,输出线程2和线程3的优先级
调试结果
题外话:
今天有人事打电话要成绩单,看到以前的成绩方知“少壮不努力,老大徒伤悲”。