嵌入式操作系统漫议:任务间通信与同步之信号量

信号量是另一种任务之间交互的机制,既可以用于控制对共享资源的访问,也可用于任务间的同步(Synchronization)。

信号量的名字据说来自铁路系统,用于确保一段铁轨在一段时间内只能有一列火车通过。这种互斥访问是通过在指定的任何时间点上只设置一个方向的信号灯为绿灯,其他所有方向的信号灯都为红灯来实现。在1965年,荷兰学者Edsger Dijkstra据此提出了信号量的概念,用于不同线程之间的同步和共享资源的访问。

信号量本质上是一个单变量(非负整数)的共享资源,如图 1所示。

 

1 信号量基本模型

对其有两个基本操作:

  • 获取操作。根据操作系统不同,其在API中可能采用take、pend等命名。如果信号量的当前值大于0,则其值减1,获取成功,立即返回。如果当前值为0,则根据API中定时时间的设定,如果定时时间大于0,则当前任务挂起,等待信号量的当前值大于零;如果定时时间为0,则立即失败返回。
  • 释放操作。根据操作系统不同,其在API中可能采用give、post等命名。该操作将当前信号量的值加1,然后返回。同时系统会检查等待该信号量的任务,找到最高优先级的任务,执行其获取操作。

操作过程参照图 2的例子。

 

图 2 对信号量的操作

信号量仅就其本身而言,没有什么意义,只有与某些操作联系起来,才有意义。这些操作,可以是对某些共享资源的访问,也可以是不同任务间的同步操作。用于不同的目的时,信号量的初值和操作流程是不同的。

首先如果信号量是一个二值变量,只能取值0或1,则根据初值的不同,可以用于任务间同步或对共享资源的访问控制。

  • 如果初值为1,则可以用于对共享资源的排他访问。对共享资源的访问操作,称为关键代码段(Critical Section)。在某个任务访问共享资源时,先获取信号量,再执行关键代码段,结束后释放信号量,如图 3所示。获取/释放操作必须成对出现,否则就会导致死锁。在有的操作系统(如FreeRTOS)中,用于排他访问的,称为互斥锁(Mutex)。

图 3 排他访问流程

  • 如果初值为0,则可以用于任务间的同步,如图 4所示。

 

图 4 二值信号量用于任务同步

在图中,实线箭头表示任务的执行流程,虚线箭头表示信号量值的改变过程,实线方框表示任务内的代码执行,点划线方框表示操作系统对当前任务的调度操作,点划线箭头表示信号量触发的调度动作。

任务2为了执行代码段2,必须首先获取信号量。但此时信号量的值为0(初值),因此操作系统将任务2挂起,等待其他任务释放信号量。任务1在执行完代码段1以后,释放信号量。此时信号量的当前值为1,任务2获取信号量成功,操作系统唤醒任务2,开始执行代码段2。因此,任务2的代码段2总是在任务1的代码段1之后执行。使得两个任务的动作完美同步。

在上图中,还可以看到,任务2只获取信号量,任务1只释放信号量。可以保证在循环执行中,上述同步动作也得到遵守。而且,这与共享资源的排他访问中必须成对出现获取/释放操作也完全不同。

信号量用户同步的一个经常的使用场景就是实现所谓的延时中断处理(Deferred Interrupt Handler)。由于中断处理函数一般运行在CPU的特权级等高优先级别,外部事件不能打断,因此终端处理程序不能占用太长的CPU运行时间。如果外部事件引起的处理时间较长,可以将它分为两个部分:与硬件相关的需要立即执行的处理(如寄存器的重置、状态变量的保存等),而将其他的处理移到高优先级Task中执行。而中断处理程序和任务之间,采用信号量进行同步。移到高优先级任务中执行的部分就是延时中断处理。

在FreeRTOS中,为这两类二值信号量准备了不同的API:用于任务同步的叫二值信号量(Binary Semaphore),用于排他访问的叫互斥锁(Mutex)。

如果是一个多值信号量,同样根据其初值的不同,可用于事件通知和资源管理。

  • 如果初值大于0,则用于资源管理。与二值信号量的排他访问类似,多值信号量用于允许一个以上的任务同时访问、但能同时访问的任务数有限制的共享资源的管理。其中可用的资源数量由信号量的初值指定。当某个任务需要访问共享资源时,其执行流程与图 3完全相同。

如一个用户定义的缓存管理系统。假设该缓存系统由10个缓存构成,用户任务调用申请函数(如BufReq())申请缓存,使用完后调用释放函数(如BufRel())释放缓存。这样一个系统就可以用多值信号量来管理。信号量的初始值设为10,每分配出一个缓存,其值减1;每释放一个缓存,其值加1。如果缓存的申请数小于10时,则申请立即返回;如果申请数达到10,则新的申请任务就被挂起,直到有缓存被释放。

  • 如果初值等于0,则用于事件通知。此时往往还需要另外一个参数,用于指定可以记录的最大事件数。事件记录与处理的流程与图 4描述的也完全类似。任务1每生成一个给任务2的事件,就调用一次释放信号量的操作,信号量值就加1。因此信号量值实际上表示已经生成等待任务2处理的事件数量。但信号量值大于等于1时,表示有事件等待处理。任务2通过获取信号量,一次循环读取一个事件,进行处理。因此通过信号量的计数,不会导致事件的丢失。

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值