FreeRTOS再学习——2nd——信号量和优先级反转问题
信号量:
信号量是操作系统中重要的一部分,信号量一般用来进行资源管理和任务同步,FreeRTOS中信号量又分为二值信号量、计数型信号量、互斥信号量和递归互斥信号量。
不同的信号量其应用场景不同,但有些应用场景是可以互换着使用的。
二值信号量只有0和1,表示信号量的两个状态,适用于立flag
信号量的另一个重要的应用场合就是任务同步,用于任务与任务或中断与任务之间的同步。裸机编写中断服务函数的时候一般都只是在中断服务函数中打个标记,然后在其他的地方根据标记来做具体的处理过程。在使用RTOS系统的时候我们就可以借助信号量完成此功能,当中断发生的时候就释放信号量,中断服务函数不做具体的处理。具体的处理过程做成一个任务,这个任务会获取信号量,如果获取到信号量就说明中断发生了,那么就开始完成相应的处理,这样做的好处就是中断执行时间很短
二值信号量,用来处理当某个事件产生后,标志某位,让某个任务进入运行态
还是上图容易理解:(大用途)
由于任务函数一般都是一个大循环,所以在任务做完相关的处理以后就会再次调用函数xSemaphoreTake()获取信号量。在执行完第三步以后二值信号量就已经变为无效的了,所以任务将再次进入阻塞态,和第一步一样, 直至中断再次发生并且调用函数xSemaphoreGiveFromISR0释放信号量。
创建二值信号量API:
释放信号量API:
获取信号量API:
使用总结:
当一个事件发生,释放信号量,也即flag=1,有一个任务在获取信号量,也就是一直在while(1),1就是信号量是否有效的标志;当事件未产生时,任务不执行,也就是在阻塞态,当中断或者其他任务释放信号量,指定任务获取到信号量,开始执行,也就是从阻塞态就如就绪态等待CPU的使用权(因为有可能有别的优先级更高的任务在执行,如果此时它的优先级最高那就是进入运行态),相比裸机:裸机轮询实时性更差点(我觉得)
计数型信号量:包括信号量和信号量值
适用于这种情况:相比二值信号量的立flag,这货可以记录立flag的次数,比如说停车场停车,停一辆车立一个flag,二值信号量只能说明有车停进来了,这货可以记录停进来几辆车。
这货是倒着计数的额,从信号量值开始倒着计数,当为0时,说明木得资源了
创建计数型信号量API:
信号量的获取和释放和二值信号量一样。
优先级反转问题:
当前有三个任务的优先分别问1、2、3。
开始的时候,1和2在挂起状态等待某一事件发生,优先级最低的3正在运行,当优先级最高的1的事件发生后,他开始运行,3先停下来,但是它访问某一共享资源时,发现3之前在用,并且3使用的这一共享资源的信号量还被3占用着,1只能等着3用完这个共享资源,CPU使用权暂时3用着,此时2的事件发生了,那么CPU使用权给2,2要做的事不用3所用的共享资源,所以2就先执行完了,然后CPU使用权给3,当3使用完和1相同的共享资源后,1开始执行,3等着,然后1执行完,3再执行。
此时,优先级为2的任务却先在任务优先级更高的1任务执行完之前执行完了,1和2个优先级就反转了。这是我的理解,看图看图
解决优先级反转之互斥信号量:(不能在中断服务函数中使用)
互斥访问中互斥信号量相当于一个钥匙,当任务想要使用资源的时候就必须先获得这个钥匙,当使用完资源以后就必须归还这个钥匙,这样其他的任务就可以拿着这个钥匙去使用资源。也就是说,只能访问一次,访问完,需要释放
互斥信号量解决优先级反转的问题的方法:
也就是说,任务1在等任务3使用那个共享资源的时候,把任务3的优先级变成1,等它使用完了再把它的优先级变回去,也就是说,2不能在1等待3执行访问和1的共享资源的的时候先执行了,只是把影响降到最低,最后还是得等3先用完共享的资源。
创建互斥信号量API:
递归互斥信号量
可以看作是一个特殊的互斥信号量,已经获取了互斥信号量的任务就不能再次获取这个互斥信号量,但是递归互斥信号量不同,已经获取了递归互斥信号量的任务可以再次获取这个递归互斥信号量,而且次数不限!一个任务使用函数xSemaphore’ TakeRecursive()成功的获取了多少次递归互斥信号量就得使用函数xSemaphoreGiveRecursive(释放多少次!比如某个任务成功的获取了5次递归信号量,那么这个任务也得同样的释放5次递归信号量。
递归互斥信号量也有优先级继承的机制,所以当任务使用完递归互斥信号量以后一定要记得释放。同互斥信号量一样,递归互斥信号量不能用在中断服务函数中。
创建递归信号量API: