基本概念:
信号量是一种实现任务间通信的机制,相当于一个标志位,能够实现任务的同步、互斥竞争资源的任务来访问临界资源(临界资源是指任何时刻只能被一个任务访问的资源)等等。作为程序来说,信号量是一个非负整数,每有任务去获取信号量都会使它减一,当信号量为0时,所有获取该信号量的任务都会处于阻塞状态。简单理解为:信号量的值代表可使用的互斥资源数,当为0时则表示没有可用的互斥资源。
***二值信号量
二值信号量可以理解为只有0/1,相当于只有一个消息的队列,因此在使用二值信号量时,可以通过队列中是否空/满就能判断是否同步,不用去关心队列中的消息到底是什么。
利用其特性,二值信号量常用于任务间的同步/中断与任务间的同步。如何实现同步呢?在消息队列章节了解到当队列没有消息的时候,任务会阻塞在队列中,直到有新消息入队(设定了等待时间),这样便可以实现任务间的同步/中断与任务间的同步。
计数信号量
计数信号量相当于长度大于1的消息队列,和二值信号量使用情况一样,不需要知道消息队列中消息是什么,我只需知道此时消息队列中还有多少消息。
计数信号量通常用于管理事件处理/资源管理的情况。其值每加一代表发生了某个事件,相反,每减一则代表处理了某个事件(处理完事件后应返还信号量)。
***互斥信号量(互斥量)
二值信号量与互斥信号量(互斥量)极为相似,是特殊的二值信号量,不同之处在于互斥量拥有优先级继承机制。
利用互斥量优先级继承机制(减小优先级翻转问题),常用于简单互锁,也就是保护临界资源。任意时刻互斥量只有开锁和闭锁两种状态,在使用临界资源时,互斥量充当访问令牌的作用,只有持有互斥量的任务才能访问临界资源,访问完成后也必须返还令牌。
递归互斥量
任务可能会多次获取互斥量的情况,使用递归互斥量可以避免同一任务多次递归持有而造成的死锁。
常用接口函数
-
创建二值信号量 xSemaphoreCreateBinary() 创建时消息队列为空,应先使用 xSemaphoreGive()释放后才可以使用xSemaphoreTake() 获取。
-
创建计数信号量 xSemaphoreCreateCounting()SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount);创建计数信号初值。
3·信号量删除函数 vSemaphoreDelete()
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore ); vSemaphoreDelete()用于删除一个信号量,包括二值信号量,计数信号量,互斥量和递归互 斥量。如果有任务阻塞在该信号量上,那么不要删除该信号量。
4·信号量释放函数xSemaphoreGive( xSemaphore )
xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken )
5·信号量获取函数xSemaphoreTake( xSemaphore, xBlockTime ) 中断函数一般不使用 获取函数。(阻塞时间)
6·xSemaphoreTakeFromISR()(中断很少使用获取信号量)
不能用来获取互斥量,因为互斥量不可以在中断中使用并且其继承优先级特性只能在任务中 起作用。
7·xSemaphoreCreateMutex()互斥量创建函数
8· 递归互斥量创建函数 xSemaphoreCreateRecursiveMutex()