信号量(semaphores)是20世纪60年代中期EdgserDijkstra发明的。使用信号量的最初目的是为了给共享资源建立一个标志,该标志表示该共享资源被占用情况。这样,当一个任务在访问共享资源之前,就可以先对这个标志进行查询,从而在了解资源被占用的情况之后,再来决定自己的行为。
实际的应用中,信号量的作用又该如何体现呢?比如有个30人的电脑机房,我们就可以创建信号量的初始化值是30,表示30个可用资源,不理解的初学者表示信号量还有初始值?是的,信号量说白了就是共享资源的数量。另外我们要求一个同学使用一台电脑,这样每有一个同学使用一台电脑,那么信号量的数值就减一,直到30台电脑都被占用,此时信号量的数值就是0。如果此时还有几个同学没有电脑可以使用,那么这几个同学就得等待,直到有同学离开,有一个同学离开,那么信号量的数值就加1,有两个就加2,依次类推。刚才没有电脑用的同学此时就有电脑可以用了,有几个同学用,信号量就减几,直到再次没有电脑可以用,这么一个过程就是使用信号量来管理共享资源的过程。
平时使用信号量主要实现以下两个功能:
u 两个任务或者中断函数跟任务之间的同步功能,这个和上章节讲解的事件标志组是类似的。其实就是共享资源为1的时候。
u 多个共享资源的管理,就像上面举的机房上机的例子。
实际上信号量还有很多其它用法,而且极具挑战性,可以大大的开拓大家的视野,有兴趣的同学可以阅读一下《The Little Book Of Semaphores》,作者是Allen B.Downy。
运行条件:
u 创建2个任务Task1和Task2。
u 创建信号量可用资源为1。
运行过程描述如下:
u 任务Task1运行过程中调用函数os_sem_wait获取信号量资源,如果信号量没有被任务Task2占用,Task1将直接获取资源。如果信号被Task2占用,任务Task1将由运行态转到挂起状态,等待资源可用。一旦获取了资源并使用完毕后会通过函数os_sem_send释放掉资源。
u 任务Task2运行过程中调用函数os_sem_wait获取信号量资源,如果信号量没有被任务Task2占用,Task1将直接获取资源。如果信号被Task2占用,任务Task1将由运行态转到挂起状态,等待资源可以。一旦获取了资源并使用完毕后会通过函数os_sem_send释放掉资源。
运行条件:
u 创建1个任务Task1和一个串口接收中断。
u 信号量的初始值为0,串口中断调用函数isr_sem_send释放信号量,任务Task1调用函数os_sem_wait获取信号量资源。
运行过程描述如下:
u 任务Task1运行过程中调用函数os_sem_wait,由于信号量的初始值是0,没有信号量资源可用,任务Task1由运行态进入到挂起态。
u Task1挂起的情况下,串口接收到数据进入到了串口中断服务程序,在串口中断服务程序中调用函数isr_sem_send释放信号量资源,信号量数值加1,此时信号量计数值为1,任务Task1由挂起态进入到就绪态,在调度器的作用下由就绪态又进入到运行态,任务Task1获得信号量后,信号量数值减1,此时信号量计数值又变成了0。
u 再次循环执行时,任务Task1调用函数os_sem_wait由于没有资源可用再次进入到挂起态,等待串口释放信号量资源,如此往复循环。
上面就是一个简单RTX中断方式信号量同步过程。实际应用中,中断方式的消息机制切记注意以下四个个问题:
u 中断函数的执行时间越短越好,防止其它低于这个中断优先级的异常不能得到及时响应。
u 实际应用中,建议不要在中断中实现消息处理,用户可以在中断服务程序里面发送消息通知任务,在任务中实现消息处理,这样可以有效的保证中断服务程序的实时响应。同时此任务也需要设置为高优先级,以便退出中断函数后任务可以得到及时执行。
u 中断服务程序中一定要调用专用于中断的信号量设置函数isr_sem_send。
u 在RTX操作系统中实现中断函数和裸机编程是一样的。
l 另外强烈推荐用户将Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407的NVIC优先级分组设置为4,即:NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);这样中断优先级的管理将非常方便。
l 用户要在RTX多任务开启前就设置好优先级分组,一旦设置好切记不可再修改。
Task Configuration
l Number of concurrent running tasks
允许创建4个任务,实际创建了如下四个任务
AppTaskUserIF任务 :按键消息处理。
AppTaskLED任务 :LED闪烁。
AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的信号量同步信号。
AppTaskStart任务 :启动任务,也是最高优先级任务,这里实现按键扫描。
l Number of tasks with user-provided stack
创建的4个任务都是采用自定义堆栈方式。