在《RT-Thread 编程指南》中,有一句关于信号量的描述,
“在信号量中,以为已经不存在实例,线程递归持有会发生主动挂起(最终形成死锁)”
不太懂什么是实例,什么是线程递归,怎样形成的死锁。
我的理解是这样的:
这句话的意思是如果一个线程不断获取信号量(没有释放的过程),当信号量的值为0后,线程就会停下,之后就无法运行了,相当于被锁住了。当然这里有个前提,别的线程无法释放这个信号量。
还是举个例子:假设信号量初始值为1,也就是二值信号量
先说正常的使用,我们可以用来保护临界区数据
void thread1_entry(void *parameter)
{
while (1)
{
/* 临 界 区, 上 锁 进 行 操 作 */
rt_sem_take(&sem_lock, RT_WAITING_FOREVER); /*获取信号量,获取成功后就可以对临界区数据写入*/
i += 1; /*这里进行数据处理,i为临界区数据*/
rt_sem_release(&sem_lock); /*释放信号量,让其他线程可以处理临界区数据*/
}
}
但是如果线程递归调用了信号量,如下面所示(例子可能举的不是很恰当,但是有些时候可能会这样使用)
void thread1_entry(void *parameter)
{
while (1)
{
/* 临 界 区, 上 锁 进 行 操 作 */
rt_sem_take(&sem_lock, RT_WAITING_FOREVER); /*获取信号量,此时信号量为被获取,变成了0*/
/*
操作临界区1
*/
rt_sem_take(&sem_lock, RT_WAITING_FOREVER); /*想再次获取,但是此时由于信号量为0,获取不到就一直等待*/
/*但是释放信号量的操作在下面,所以信号量根本释放不了,这个线程就锁死在上面那句语句,成了解不开的死锁。
所以下面的部分永远不会执行到*/
/*
操作临界区2
*/
rt_sem_release(&sem_lock); /*释放信号量,让其他线程可以处理临界区数据*/
rt_sem_release(&sem_lock); /*释放信号量,让其他线程可以处理临界区数据*/
}
}
正因为这样,所以互斥量解决了这个问题,在保护临界区数据时,最好使用互斥量,尤其其解决优先级翻转的问题