任务之间的同步与通信( 二 )


1.信号量
信号量是一类事件 。使用信号量的最初目的,是为了给共享资源设立一个标志,该标志表示该共享资源被占用情况 。这样,当一个任务在访问共享资源之前,就可以先对这个标志进查询,从而在了解资源被占用的情况之后再来决定自己的行为 。
观察一下人们日常生活中常用的一种共享资源公用电话亭的使用规则,就会发现这种规则很适合在协调某种资源用户关系时使用 。如果一个电话亭只允许一个人进去打电话,那么电话亭的门上就应该有一个可以变换两种颜色的牌子(例如,用红色表示“有人”,用绿色表示“无人”) 。当有人进去时,牌子会变成色;出来时,牌子又会变成绿色 。这样来打电话的人就可根据牌子的颜色来了解电话亭的被占用情况 。路口上的交通信号灯,所以人们最初给这种标志起的名称就是信号灯,后来因为它含有了量的概念,所以又叫做信号量 。
显然,对于上面介绍的红绿标志来说,这是一个二值信号量,而且由于它可以实现共享资源的独占式占用,所以被叫做互斥型信号量 。
如果电话亭可以允许多人打电话,那么电话亭门前就不应该是那种只有红色和绿色两种颜色状态的牌子,而应该是一个计数器,计数器在每进去一个人时会自动减1,而每出去个人时会自动加1 。如果其初值按电话亭的最大容量来设置,那么来人只要见到计数器的值大于0,就可以进去打电话;否则只好等待这种计数式的信号叫做信号量
上图两个任务在使用互斥型信号量进行通信,从而可使这两个任务无冲突地访问共享资源的示意图 。任务1在访问共享资源之前先进行请求信号量的操作,当任务1发现信号量的标志为“1”时,它一方面把信号量的标志由“1”改为“0”,访问共享资源 。任务2在任务1已经获得信号之后来请求信号量,那么由于它获得的标志值是“0”所以任务2就只有等待而不能访问共享资源了 。显然,这种做法可以有效地止两个任务同时访问同一个共享资源所造成的冲突 。
那么任务2何时可以访问共享资源呢?当然是在任务1使用完共享资源之后,由任务向信号量发信号使信号量标志的值由“0”再变为“1”时,任务2就有机会访问共享资源了 。与任务1一样,任务2一旦获得了共享资源的访问权,那么在访问共享资源之前一定要把信号量标志的值由“1”变为“0” 。
2.消息邮箱
在多任务操作系统中,常常需要在任务与任务之间通过传递一个数据(这种数据叫做“消息”)的方式来进行通信 。为了达到这个目的,可以在内存中创建一个存储空间作为该数据的缓冲区 。如果把这个缓冲区叫做消息缓冲区,那么在任务间传递数据(消息)的一个最简单的方法就是传递消息缓冲区的指针 。因此,用来传递消息缓冲区指针的数据结构就叫做消息邮箱 。
上图两个任务使用消息邮箱进行通信的示意图 。任务1在向消息邮箱发送消息,任务2在从消息邮箱读取消息 。读取消息也叫做请求消息 。
3.消息队列
上面谈到的消息邮箱不仅可用来传递一个消息,而且也可定义一个指针数组 。让数组的每个元素都存放一个消息缓冲区指针,那么任务就可通过传递这个指针数组指针的方法来传递多个消息了 。这种可以传递多个消息的数据结构叫做消息队列 。
上图是两个任务使用消息队列进行通信的示意图 。任务1向消息队列发送消息缓冲区指针数组的指针,这个操作叫做发送消息队列;任务2在从消息队列读取消息缓冲区指针数组的指针,这个操作叫做请求消息队列 。
三:事件控制块级相关操作函数
所有的通信信号都被看成是事件(event), uC/OS-II通过事件控制块(ECB)来管理每一个具体事件 。