第21章
FreeRTOS计数信号量
本章节开始讲解FreeRTOS任务间的同步和资源共享机制,计数信号量。FreeRTOS中计数信号量的源码实现是基于消息队列实现的。
本章教程配套的例子含Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407以及F429。
21.1
信号量
21.2
计数信号量API函数
21.3
实验例程说明(任务间通信)
21.4
实验例程说明(中断方式通信)
21.5
总结
21.1信号量
21.1.1 信号量的概念及其作用
信号量(semaphores)是20世纪60年代中期Edgser
Dijkstra发明的。使用信号量的最初目的是为了给共享资源建立一个标志,该标志表示该共享资源被占用情况。这样,当一个任务在访问共享资源之前,就可以先对这个标志进行查询,从而在了解资源被占用的情况之后,再来决定自己的行为。
实际的应用中,信号量的作用又该如何体现呢?比如有个30人的电脑机房,我们就可以创建信号量的初始化值是30,表示30个可用资源,不理解的初学者表示信号量还有初始值?是的,信号量说白了就是共享资源的数量。另外我们要求一个同学使用一台电脑,这样每有一个同学使用一台电脑,那么信号量的数值就减一,直到30台电脑都被占用,此时信号量的数值就是0。如果此时还有几个同学没有电脑可以使用,那么这几个同学就得等待,直到有同学离开。有一个同学离开,那么信号量的数值就加1,有两个就加2,依此类推。刚才没有电脑用的同学此时就有电脑可以用了,有几个同学用,信号量就减几,直到再次没有电脑可以用,这么一个过程就是使用信号量来管理共享资源的过程。
平时使用信号量主要实现以下两个功能:
(1)两个任务之间或者中断函数跟任务之间的同步功能,这个和前面章节讲解的事件标志组是类似的。其实就是共享资源为1的时候。
(2)多个共享资源的管理,就像上面举的机房上机的例子。
针对这两种功能,FreeRTOS分别提供了二值信号量和计数信号量,其中二值信号量可以理解成计数信号量的一种特殊形式,即初始化为仅有一个资源可以使用,只不过FreeRTOS对这两种都提供了API函数,而像RTX,uCOS-II和III是仅提供了一个信号量功能,设置不同的初始值就可以分别实现二值信号量和计数信号量。当然,FreeRTOS使用计数信号量也能够实现同样的效果。
实际上信号量还有很多其它用法,而且极具挑战性,可以大大的开拓大家的视野,有兴趣的同学可以阅读一下《The
Little Book Of Semaphores》,作者是Allen
B. Downy。
本章节主要为大家讲解计数信号量。
21.1.2FreeRTOS任务间计数信号量的实现
任务间信号量的实现是指各个任务之间使用信号量实现任务的同步或者资源共享功能。下面我们通过如下的框图来说明一下FreeRTOS计数信号量的实现,让大家有一个形象的认识。
运行条件:
u
创建2个任务Task1和Task2。
u
创建计数信号量可用资源为1。
运行过程描述如下:
u
任务Task1运行过程中调用函数xSemaphoreTake获取信号量资源,如果信号量没有被任务Task2占用,Task1将直接获取资源。如果信号量被Task2占用,任务Task1将由运行态转到阻塞状态,等待资源可用。一旦获取了资源并使用完毕后会通过函数xSemaphoreGive释放掉资源。
u
任务Task2运行过程中调用函数xSemaphoreTake获取信号量资源,如果信号量没有被任务Task1占用,Task2将直接获取资源。如果信号量被Task1占用,任务Task2将由运行态转到阻塞状态,等待资源可用。一旦获取了资源并使用完毕后会通过函数xSemaphoreGive释放掉资源。
上面就是一个简单的FreeRTOS任务间计数信号量的使用过程。
21.1.3FreeRTOS中断方式计数信号量的实现
FreeRTOS中断方式信号量的实现是指中断函数和FreeRTOS任务之间使用信号量。信号量的中断方式主要是用于实现任务同步,与前面章节讲解事件标志组中断方式是一样的。
下面我们通过如下的框图来说明一下FreeRTOS中断方式信号量的实现,让大家有一个形象的认识。
运行条件:
u
创建一个任务Task1和一个串口接收中断。
u
信号量的初始值为0,串口中断调用函数xSemaphoreGiveFromISR释放信号量,任务Task1调用函数xSemaphoreTake获取信号量资源。
运行过程描述如下:
u
任务Task1运行过程中调用函数xSemaphoreTake,由于信号量的初始值是0,没有信号量资源可用,任务Task1由运行态进入到阻塞态。
u
Task1阻塞的情况下,串口接收到数据进入到了串口中断服务程序,在串口中断服务程序中调用函数xSemaphoreGiveFromISR释放信号量资源,信号量数值加1,此时信号量计数值为1,任务Task1由阻塞态进入到就绪态,在调度器的作用下由就绪态又进入到运行态,任务Task1获得信号量后,信号量数值减1,此时信号量计数值又变成了0。
u
再次循环执行时,任务Task1调用函数xSemaphoreTake由于没有资源可用再次进入到阻塞态,等待串口释放信号量资源,如此往复循环。
上面就是一个简单的FreeRTOS中断方式信号量同步过程。实际应用中,中断方式的消息机制要注意以下四个问题:
u
中断函数的执行时间越短越好,防止其它低于这个中断优先级的异常不能得到及时响应。
u
实际应用中,建议不要在中断中实现消息处理,用户可以在中断服务程序里面发送消息通知任务,在任务中实现消息处理,这样可以有效地保证中断服务程序的实时响应。同时此任务也需要设置为高优先级,以便退出中断函数后任务可以得到及时执行。
u
中断服务程序中一定要调用专用于中断的信号量设置函数,即以FromISR结尾的函数。
u
在操作系统中实现中断服务程序与裸