互斥信号量
我们之前学习的信号量是一个独立的信号量,什么是互斥信号量呢?在了解互斥信号量之前我么了解一下什么是优先级反转:
优先级反转
在第五步之后,因为信号量被任务L占有,所以任务H无法等待到信号量,最后任务L被任务M剥夺,这种情况发生,我们会发现任务H必须等待任务M运行完再将信号量释放之后才能开始运行;这样就导致了优先级反转这个概念。
为了避免优先级反转这个问题,UCOSIII支持一种特殊的二进制信号量:互斥信号量, 用它可以解决优先级反转问题:
我们可以看到,在使用互斥信号量之后,从第五步开始,任务H在没有等待到互斥信号量的时候,暂且将任务L的优先级提升到和自己的优先级一样,然后运行任务L,直到它将互斥信号量释放,任务H再继续运行,这样就解决的优先级反转的问题。
互斥信号量相关API函数
和普通信号量的形式是差不多的,重要的即是标红的三个函数;
//创建一个互斥信号量
void OSMutexCreate (OS_MUTEX *p_mutex,//和普通信号量一样,互斥信号量结构体指针
CPU_CHAR *p_name, //互斥信号量名字
OS_ERR *p_err) //错误码
//等待一个互斥信号量
void OSMutexPend (OS_MUTEX *p_mutex, //互斥信号量结构体指针
OS_TICK timeout, //等待互斥信号量的超时时间(节拍数),timeout = 0,任务一直等待直到信号量释放
OS_OPT opt, /*是否为阻塞模式
OS_OPT_PEND_BLOCKING 信号量被占用,任务挂起等待
OS_OPT_PEND_NON_BLOCKING 信号量被占用直接返回
*/
CPU_TS *p_ts, //时间戳,指向记录发送、终止、删除信号量的时刻
OS_ERR *p_err) //错误码
//释放一个互斥信号量
void OSMutexPost (OS_MUTEX *p_mutex,//互斥信号量结构体指针
OS_OPT opt, /*指定是否进行任务调度
OS_OPT_POST_NONE 不指定特定选项
OS_OPT_POST_NO_SCHED 禁止任务调度
*/
OS_ERR *p_err) //错误码
使用
在开始任务中创建完一个互斥信号量之后,我们在一个高优先级任务和一个低优先级任务中使用,使用的方法和独立信号量一样:
//高优先级任务的任务函数
void high_task(void *p_arg)
{
OS_ERR err;
while(1)
{
OSMutexPend (&TEST_MUTEX,0,OS_OPT_PEND_BLOCKING,0,&err); //请求互斥信号量
......
OSMutexPost(&TEST_MUTEX,OS_OPT_POST_NONE,&err); //释放互斥信号量
}
}
//低优先级任务的任务函数
void low_task(void *p_arg)
{
OS_ERR err;
while(1)
{
OSMutexPend (&TEST_MUTEX,0,OS_OPT_PEND_BLOCKING,0,&err);//请求互斥信号量
......
OSMutexPost(&TEST_MUTEX,OS_OPT_POST_NONE,&err); //释放互斥信号量
}
}
任务内嵌信号量
任务内嵌信号量是在一个任务被创建的时候,会自动创建一个任务内嵌信号量,使用任务内嵌信号量可以大大优化我们的代码;
API函数
看到API函数我们就知道,因为在UCOSIII中每一个任务都有自己的任务内嵌信号量,所以它是不需要创建的。
//等待一个任务信号量
OS_SEM_CTR OSTaskSemPend (OS_TICK timeout, //等待信号量的超时时间(节拍数)
OS_OPT opt, /*是否为阻塞模式
OS_OPT_PEND_BLOCKING 信号量被占用,任务挂起等待
OS_OPT_PEND_NON_BLOCKING 信号量被占用直接返回
*/
CPU_TS *p_ts, //时间戳
OS_ERR *p_err) //错误码
注意:等待任务内嵌信号量的这个函数只能用在自己的任务函数之中
,我们根据这个函数可以发现,它没有信号量指针。
//释放或发送一个信号量
OS_SEM_CTR OSTaskSemPost (OS_TCB *p_tcb,//任务控制块
OS_OPT opt, /*指定是否进行任务调度
OS_OPT_POST_NONE 不指定特定选项
OS_OPT_POST_NO_SCHED 禁止任务调度
*/
OS_ERR *p_err)//错误码
发送信号量就没有那么多限制,可以在其他的任务函数中调用它。
它的使用除了有一个限制之外也和其他信号量一样。
总结
我们会发现,独立信号量、互斥信号量、任务内嵌信号量他们的使用方法是很类似的,都是创建、发送、等待这三步,其中任务内嵌它不需要创建是因为任务函数自带,其中相同功能的函数中的参数也基本上是一样的,只是他们用于解决问题的场景不同。
独立信号量:
1.保护共享资源
2.目前更多用于任务同步
互斥信号量:
用于解决优先级反转
任务内嵌信号量:
简化代码、更加高效
希望我的文章会对你有帮助!下次见;