UCOS学习(八)——互斥信号量和任务内嵌信号量

互斥信号量

我们之前学习的信号量是一个独立的信号量,什么是互斥信号量呢?在了解互斥信号量之前我么了解一下什么是优先级反转:

优先级反转

在这里插入图片描述
在第五步之后,因为信号量被任务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.目前更多用于任务同步
互斥信号量
用于解决优先级反转
任务内嵌信号量
简化代码、更加高效
希望我的文章会对你有帮助!下次见;

猜你喜欢

转载自blog.csdn.net/qq_52608074/article/details/122466806
今日推荐