一、基本介绍
信号量是对公共资源状态的描述的标识,他表示在多个任务同时访问某种公共资源时,该资源是否有剩余的资源可供使用。例如停车场的车位,如果还有车位,那么信号量就可以表示有多少剩余车位。同样地,释放和占用信号量就表示对资源的释放和占用,例如车辆出库和入库。
在FreeRTOS中,信号量的本质就是队列长度为n,但是队列项的大小为0的一个队列。uxMessagesWaiting这个成员变量,在队列中,该变量的值标识队列当中有多少个队列项,而在信号量中,其表示信号量剩余的资源数。
信号量有很多种,包括但不限于二值信号量、计数信号量和互斥信号量等。
二、信号量介绍
所有的信号量除了创建的函数略有差异外,对于信号量的释放和获取都使用同一个函数,函数的使用可以参考FreeRTOS官网:FreeRTOS semaphore and mutex API functions vSemaphoreCreateBinary, xSemaphoreCreateCounting, xSemaphoreCreateMutex, xSemaphoreCreateRecursiveMutex, xSemaphoreTake, xSemaphoreTakeRecursive, xSemaphoreGive, xSemaphoreGiveRecursive, xSemaphoreGiveFromISR
1.二值信号量
二值信号量,顾名思义,只存在空和满两种情况,本质是队列长度为1的队列,二值信号量通常用于互斥访问或任务同步,与后面介绍的互斥信号量较为相似,但是二值信号在使用过程中有时候会存在优先级翻转的现象发生,所以二值信号量更适合同步任务。
优先级翻转指的是高优先级的任务因为某种原因反而慢执行,而低优先级的任务反而优先执行,而在使用二值信号量时,就会遇到优先级翻转的问题,起如下图所示
2.计数信号量
计数型信号量队列长度大于1,因此能工容纳多个资源,能表示资源的剩余情况。一般来说技术型信号量适用事件计数和资源管理两种场合。
对于事件计数,当某事件发生时,计数型信号量+1,当其他任务获取该信号量时,如果有,则-1,没有则等待。这种情况下,计数型信号量的值初始化为0
对于资源管理,信号量表示可以使用的资源数目。任务必须先获取信号量才能控制该资源。当计数值为0时表示没有资源可以使用。任务使用完该资源后,必须释放该信号量+1。因此,这种情况下,计数型信号量应初始化为最大资源数。
3.互斥信号量
互斥信号量也是一个二值信号量,不过其拥有优先级继承的能力,所以更适合使用在需要互斥方位的应用中。
优先级继承:当一个互斥信号量正在被一个低优先级的任务持有时, 如果此时有个高优先级的任务也尝试获取这个互斥信号量,那么这个高优先级的任务就会被阻塞。不过这个高优先级的任务会将低优先级任务的优先级提升到与自己相同的优先级。
三、问题与总结
1.互斥信号量在创建时就会默认释放一次,而二值和计数都需要手动释放。
2.互斥信号量不能在中断服务函数中使用,因为中断服务函数不是任务,没有任务优先级。