2020/6/191实时嵌入式操作系统Real-timeEmbeddedOperatingSystem艾云峰aiyunfeng@gmail.comCollegeofComputing&CommunicationEngineering2020/6/192主要内容-信号量的实现及使用1.什么是任务间的同步?2.RTOS中实现任务间同步的主要机制-信号量3.UC/OS-II中信号量的实现机制注:本节内容请参考Real-timeConceptsforEmbeddedSystems一书的第6章和MicroC/OS-IITheReal-TimeKernel(SecondEdition)一书的第6、7章。2020/6/193任务间的同步任务间的同步是指多个任务按照要求来协调相互之间的运行同步包括资源同步和活动同步资源同步-多任务访问共享资源时必须按照一定的顺序,以维护共享资源的完整性,此过程称为资源同步活动同步-一个任务必须使它的活动与其它任务同步,以合理的执行多任务程序;活动同步保证协同运行的各任务具有正确的执行次序2020/6/194任务间的同步例子(1)Wait-and-SignalSynchronization假设有两个不同优先级的任务:task1和task2,并且task1的优先级高于task2的优先级。假定task1和task2之间不需要数据交换,但是高优先级的任务task1必须在得到低优先级任务task2的通知之后才能执行,这种同步叫做Wait-and-SignalSynchronization。2020/6/195任务间的同步例子(2)Multiple-TaskWait-and-SignalSynchronization假设有多个不同优先级的任务task1~task4(它们之间的优先级顺序是:task1task2task3task4),并且task1、task2、task3必须在得到task4的通知后才能执行,这种同步叫做Multiple-TaskWait-and-SignalSynchronization上述两种同步都可以通过信号量来实现,那么什么是信号量?RTOS中的信号量是如何实现的呢?下面我们来学习这些内容!2020/6/196主要内容-信号量的实现及使用1.什么是任务间的同步?2.RTOS中实现任务间同步的主要机制-信号量信号量的定义信号量的类型信号量的典型操作信号量的典型应用3.UC/OS-II中信号量的实现机制2020/6/197信号量定义Asemaphore(sometimescalledasemaphoretoken)isakernelobjectthatoneormoretasksofexecutioncanacquireorreleaseforthepurposesofsynchronizationormutualexclusion.一个信号量是一个内核对象,一个或多个运行的任务可以通过获取或者释放它,达到同步或者相互排斥的目的。2020/6/198信号量对象当某个信号量首次被创立时,内核分配给它一个相关的信号量控制块SCB、一个唯一的信号量名字或者ID、一个初值(二进制或者一个计数)和一个任务等待列表。2020/6/199信号量的描述内核管理信号量信号量就像允许任务执行某些操作或者访问某个资源的钥匙,如果任务获取了该信号量(钥匙),它就可以执行这些操作或者访问该资源一个信号量可以被获得多次,内核通过维护令牌计数器跟踪信号量被获取和释放的次数。该计数器被初始化成信号量建立时的初值,当某个任务获取信号量时,该计数器减1;当一个任务释放信号量时,该计数器加1如果计数器减到0,则信号量没有剩余了,此时当有任务请求信号量时,如果它允许等待操作,则内核会把它放入任务等待队列表,任务从运行态转换到等待态。当有任务释放了信号量后,内核则以FIFO或者优先级顺序从任务等待列表中选取一个任务,使之获取该信号量。如果该任务已经是当前最高优先级的任务,则内核把它转入运行态;否则,转入就绪态,直到它成为优先级最高的任务再开始执行2020/6/1910二值信号量(binarysemaphore)一个二值信号量只能取值0或1二值信号量的状态当一个二值信号量的值为0时,认为信号量是不可使用(unavailable)的当一个二值信号量的值为1时,认为信号量是可使用(available)的二值信号量的状态转换图二值信号量首次建立时,可以初始化为可使用的或者不可使用的二值信号量被当作全局资源,允许任何任务甚至是开始没有获取过它的任务释放它2020/6/1911计数式信号量(countingsemaphore)(1)一个计数式信号量可取值0或大于0的其它值,并用令牌计数器表示其取值。计数式信号量的状态如果令牌计数器是0,则处于不可使用的状态如果令牌计数器大于0,则处于可使用的状态,令牌计数器等于它的个数计数式信号量创立时,可赋初值为0或者大于0的数计数式信号量状态转换图:2020/6/1912计数式信号量(2)计数式信号量是全局资源,可以被需要它们的所有任务共享。这个特征允许任意任务释放一个计数式信号量,即使做此任务没有获取过令牌计数信号量允许实现的计数是有界的或者无界的一个有界的计数是一个计数,当信号量首次建立时,为计数信号量设置的初值为信号量的最大计数一个无界的计数允许计数信号量的取值超过初始值,直到计数的数据类型的最大值2020/6/1913互斥信号量(MutexSemaphore)定义一个互斥信号量是一个特殊的二值信号量,其状态是开锁(unlocked)或闭锁(locked)(分别是0或1)互斥信号量最初建立为开锁状态,此时它可被某个任务获取。当它被获取后,状态转为闭锁状态;当该任务释放信号量后,其状态转为开锁状态当互斥信号量处于闭锁状态时,只有获取该信号量的任务才能释放互斥信号量没有获取互斥信号量的任务无法释放该信号量2020/6/1914典型的信号量操作创立和删除信号量获取或释放信号量清除信号量的任务等待列表获取信号量的信息2020/6/1915创立和删除信号量要注意的事情:如果一个内核支持不同类型的信号量,则可以使用不同的调用来创立二值、计数和互斥信号量二值-说明初始信号量状态和任务等待命令计数-说明初始信号量的计数和任务等待命令互斥-说明任务等待命令以及使任务删除安全、递归和优先权倒置避免协议信号量可以在任何任务中用它们的ID和信号量删除调用来删除。删除一个信号量与释放它不同;当一个信号量被删除时,任务等待列表中阻塞的所有任务不再阻塞,并且迁移到就绪状或运行状态2020/6/1916获取或释放信号量(1)根据不同内核,获取和释放一个信号量的操作可能具有不同的名称,如开启/放弃(take/give)、sm_p/sm_v、悬挂/邮贴(suspend/post)、闭锁/开锁(lock/unlock)等任务典型的采用如下之一的方法请求获取一个信号量永远等待-任务处于阻塞状态直到能够获取一个信号量等待超时-任务处于阻塞状态直到能获取一个信号量或者直到一个设定的超时时间间隔。此时,内核将任务从信号量的任务等待列表中移出并且放到就绪状态或者运行状态不等待-任务请求获取一个信号量,但是如果不能使用,任务不堵赛2020/6/1917获取或释放信号量(2)任何任务可以释放一个二值或计数式信号量;然而,一个互斥信号量只能被首次获取(锁住)了它的任务释放设计应用时,必须小心的使用信号量的释放函数。不正确的释放一个二值或计数式信号量,将造成丢失对一个共享资源的互斥访问,或造成一个I/O设备的失灵例如,任务1通过获取二值信号量对共享资源进行访问,而任务2偶然的执行了释放那个信号量的操作,这导致潜在的允许任务3取获取信号量对共享资源进行访问,从而造成对共享资源的破坏2020/6/1918清除信号量的任务等待列表为了清除一个信号量任务等待列表的所有任务,有的内核支持flush操作:Flush操作的使用场景假设一个开发者需要多个任务首先完成某些特定的工作,然后在某个共同的时间点再一起参与下一轮的调度上述要求的实现方式:要求同步的每个任务首先完成自己的工作,然后去获取同一个的状态为不可使用的信号量,从而进入堵塞状态。利用一个任务定期(该周期能保证所有要求同步的任务都已经阻塞)对该信号量进行flush操作,从而可释放所有的等待任务,使之一齐进入就绪状态。2020/6/1919获取信号量的信息在应用程序设计的某些点上,开发者需要获取信号量信息完成监视或调试。在这种情况下,可以使用下表的操作:2020/6/1920典型的信号量应用无论对于资源同步还是活动同步,信号量都是非常有用的。我们下面列举几个例子来描述不同类型信号量在任务同步设计中的应用。具体如下wait-and-signalsynchronizationmultiple-taskwait-and-signalsynchronizationcredit-trackingsynchronizationsingleshared-resource-accesssynchronizationmultipleshared-resource-accesssynchronization2020/6/1921wait-and-signalsynchronization一个任务在得到另外一个任务的通知后再开始执行。可以使用二值信号量来实现,如图所示:高优先级任务低优先级任务在上图中,tWaitTask必须在得到tSignalTask的通知后才能运行,实现步骤如下:1.建立初值为0的二值信号量2.较高优先级的tWaitTask企图去获取信号量,从而堵塞3.较低优先级的tSignalTask运行,并在运行完特定操作后,执行释放信号量的操作4.tWaiTtASK脱离任务等待列表,并抢占tSignalTask2020/6/1922multiple-taskwait-and-signalsynchronization多个任务在某个共同的时刻开始同步。可以通过对二值信号量的任务等待列表使用flush操作,如图所示:实现步骤:1.建立初值为0的二值信号量2.较高优先级的任务tWaitTask1~tWaitTask3现完成自己的处理,然后去获取信号量,从而阻塞;3.tSignalTask有机会完成自己的处理,并对信号量执行flush操作,使tWaitTask1~tWaitTask3同时脱离任务等待列表2020/6/1923credit-trackingsynchronization(1)假设有两个任务tSignalTasktWaitTask,tSignalTask负责接收数据,tWaitTask负责处理数据,tSignalTask每次接收的数据都要由tWaitTask进行处理。由于数据的到来速率是不均衡的,在大批量数据到来的时候,tSignalTask的执行速率要比tWaitTask快,为了跟踪tWaitTask接收数据包的次数,可以采用信用追踪的同步机制。如图所示:实现方式创立初值为0的计数式信号量tWaitTask处理数据之前执行获取信号量操作而堵塞tSignalTask接收完数据后,执行释放信号量操作,并延时自己,使tWaitTask开始运行;当tSignalTask执行速率快时,计数信号灯不断增长;当执行速率慢时,tWaitTask可以追赶上tSignalTask,耗尽信号量,进入堵塞状态,直到tSignalTask再一次释放信号量2020/6/1924credit-trackingsynchronization(2)伪代码实现:voidmain(){建立初值为0的信号量………}VoidtWaitTask(){……for(;;){获取信号量;处理数据;delay(5);}VoidtSingalTask(){……for(;;){if(有数据){receivedata;释放信号量;}delay(1);}假定:tSinalTask优先级大于t