文章目录
互斥量
互斥量又叫相互排斥的信号量,是一种特殊的二值信号量。互斥量类似于只有一个车位的停车场:当有一辆车进入的时候,将停车场大门锁住,其他车辆在外面等候。当里面的车出来时,将停车场大门打开,下一辆车才可以进入。
一、互斥量工作机制
互斥量的状态只有两种,开锁或闭锁。用互斥量处理不同线程对临界资源的同步访问时,获取互斥量才可以对资源进行访问,互斥量的所有权只能由一个线程所掌握,其他线程无法干涉。当线程1持有时,互斥量的状态为闭锁状态,其他线程禁止访问;线程1释放互斥量时,互斥量的状态为开锁状态,线程1失去所有权,所有线程要使用资源,按照优先级获取互斥量。
1、优先级反转问题
优先级反转问题:当使用信号量时,高优先级的线程尝试通过信号量访问资源时,如果当信号量已经被低优先级访问,低优先级运行程序时被中优先级线程卡住,无法运行完释放信号量,导致高优先级无法从低优先级手中拿取信号量,违背了线程按照优先级大小使用资源的初衷。
如果低优先级被更高优先级卡住,无法运行完,这不算优先级反转
2.优先级继承机制
优先级继承算法:暂时提高
某个占有某种资源的低优先级线程
的优先级,使之与在所有等待该资源的线程中优先级最高那个线程
的优先级相等
,而当这个低优先级
线程执行完毕释放
该资源时,优先级重新回到初始设定值
。因此,继承优先级的线程避免了系统资源被任何中间优先级的线程抢占。
3.示例图分析
1.优先级反转
优先级反转(A线程表示这个大哥当不了)
见图分析
系统中有A、B、C三个线程,优先级依次降低
- A、B线程等待事件触发,C线程被事件触发,C获取共享资源M
- A线程被事件触发,插入就绪链表,因为最高优先级,A线程运行尝试获取M资源,因为M被C线程占据,A线程挂起等待C线程释放M
- C线程运行一段时间后,B线程就绪,优先级比C线程高并且不需要使用M资源,C线程让出处理器,B线程运行
- B线程运行完,A线程启动无M资源挂起(相当于A线程没运行),C线程继续运行知道释放M资源
- A线程启动获得M资源,继续运行
总结A线程因为M资源的原因,无法运行,而占据M资源的C线程,因为优先级低,需要让出处理器给不需要M资源的B线程。A线程表示我等C线程就算了,毕竟M资源(人质)在他手上,B线程你算什么,要老子等你
2.优先级继承
优先级继承(C线程的狐假虎威)
见图分析
系统中有A、B、C三个线程,优先级依次降低
- A、B线程等待事件触发,C线程被事件触发,C获取共享资源M
- A线程被事件触发,插入就绪链表,因为最高优先级,A线程运行尝试获取M资源,因为M被C线程占据,A线程挂起等待C线程释放M
- 将C线程的优先级存在互斥量控制块中的original_priority,A线程给C线程相同的优先级
- B线程就绪,C优先级=A优先级>B优先级,B无法抢占,C线程继续运行
- C线程运行完释放M资源,并且取回自己优先级,按照优先级链表排序,A线程运行,A获取M资源
- A线程运行完,才轮到B线程
总结A线程因为M资源在C线程手中,忍痛给C线程相同优先级,C线程狐假虎威让B线程不敢妄动,B线程表示看在A线程面子上,让你一次
4代码分析
1.互斥量控制块
互斥量总控制台
struct rt_mutex
{
struct rt_ipc_object parent; //继承自 ipc_object 类
rt_uint16_t value; //互斥量的值
rt_uint8_t original_priority; //持有线程的原始优先级
rt_uint8_t hold; //持有线程的持有次数
struct rt_thread *owner; //当前拥有互斥量的线程
};
typedef struct rt_mutex *rt_mutex_t;
2互斥量管理图
代码来自ipc.c
3初始化和脱离
初始化
静态互斥量对象的内存是在系统编译时由编译器分配的,一般放于读写数据段或未初始化数据段中。在使用这类静态互斥量对象前,需要先进行初始化
rt_err_t rt_mutex_init(rt_mutex_t mutex, const char *name, rt_uint8_t flag)
{
/* parameter check */
RT_ASSERT(mutex != RT_NULL);//参数核查是否为互斥量
/* init object */
rt_object_init(&(mutex->parent.parent), RT_Object_Class_Mutex, name);//初始化互斥量对象
/* init ipc object */
rt_ipc_object_init(&(mutex->parent));//初始化ipc对象
mutex->value = 1; //互斥量值为1
mutex->owner = RT_NULL; //持有互斥量线程为空
mutex->original_priority = 0xFF; //持有线程原始优先级为0xff
mutex->hold = 0; //持有数为0
/* set flag */
mutex->parent.parent.flag = flag; //设置标志位
return RT_EOK;
}
RTM_EXPORT(rt_mutex_init);
脱离(不删内存)从对象容器中脱离
rt_err_t rt_mutex_detach(rt_mutex_t mutex)
{
/* parameter check */
RT_ASSERT(mutex != RT_NULL);//参数核查是否为互斥量
RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex);//判断对象是否为互斥量
RT_ASSERT(rt_object_is_systemobject(&mutex->parent