VxWorks学习笔记——任务间通信之信号量

VxWorks为保证各个独立的任务可以协同工作,提供了一整套任务的通信机制,包括信号量、共享内存、消息队列、管道、信号、事件等,此外还有一些网络编程机制如套接字。本文主要对信号量进行总结介绍。

信号量简介

  • 定义:信号量是实现任务互斥、同步操作的主要机制。在各种任务间通信机制中,速度最快。
  • 功能:
    • 互斥:不同任务可以利用信号量互斥地访问临界资源。这种互斥的访问方式比中断禁止与优先级锁定两种互斥方式更精确。
    • 同步:一个任务可以利用信号量控制自己的执行进度,使自己同步于一组外部事件。
  • 种类:
    • 二进制信号量:完成互斥、同步操作的最佳方式,速度最快,最常用。
    • 互斥信号量:特殊的二进制信号量,专门针对互斥操作进行优化。新特性有优先级继承、删除保护与递归访问。
    • 技术信号量:类似于二进制信号量,可记录信号量释放的次数,可监视统一资源的多个实例。
  • 控制接口:
    • semBCreate():创建二进制信号量
    • semMCreate():创建互斥信号量
    • semCCreate():创建计数信号量
    • semDelete():删除并释放信号量
    • semTake():获取一个信号量
    • semGive():释放一个信号量
    • semFlush():将所有等待该信号量的任务唤醒

二进制信号量

状态

二进制信号量有两种状态,分别为SEM_FULLSEM_EMPTY,前者表示信号量可用,后者表示信号量不可用

常用函数

  • semBCreate(int option, SEM_B_STATS initialState):创建信号量。前一个参数决定任务在二进制信号量上的排队方式,可选SEM_Q_PRIORITYSEM_Q_FIFO。后一个参数决定信号量的初始状态,可选SEM_FULLSEM_EMPTY
  • semDelete(SEM_ID semId):删除二进制信号量。
  • semTake(SEM_ID semId, int timeout):获取信号量。前一个参数表示信号量ID,后一个参数表示超时时间,即阻塞时间,如果任务因为得不到信号量而阻塞,参数决定阻塞的最长时间。timeout有两个特殊的取值:
    • 当值为NO_WAIT(0)时,调用任务不阻塞;
    • 当值为WAIT_FOREVER(-1)时,任务将永久阻塞等待,直至获取信号量(出得该信号量被删除或者被semFlush()唤醒)。
    • 注:ISR不能调用semTake操作。
  • semGive(SEM_ID semId):释放信号量。
  • semFlush(SEM_IF semId):唤醒阻塞在某信号量上的所有任务。执行时不改变该二进制信号量所处的状态,而是清空阻塞在该信号量上的任务队列,将所有等待该信号量的任务唤醒。

使用二进制信号量实现互斥与同步

  • 互斥:
    • 初始状态设为可用;
    • 在同一个任务中,成对调用semTake和semGive。
  • 同步:
    • 初始状态设为不可用;
    • 在不同任务中分别单独调用semTake和semGive。

互斥信号量

与二进制信号量的区别

  • 互斥信号量只能用于互斥操作,不可用于同步操作;
  • 互斥信号量只能由获得获得互斥信号量的任务去释放;
  • ISR不可以释放互斥信号量;
  • 互斥信号量不支持semFlush()操作。

比二进制信号量多出来的特性

互斥信号量同样具有两个状态,只不过其初始状态只能指定为可用,所以只有options这一个参数

  • 避免优先级倒置:参数设置为SEM_Q_PRIORITY SEM_INVERSION_SAFE;
  • 保证删除安全:SEM_Q_FIFO SEM_DELETE_SAFE 或者SEM_Q_PRIORITY SEM_DELETE_SAFE;
  • 实现资源的递归访问。一个互斥信号量可以被占有它的任务反复进行semTake而不引起该任务的阻塞。一个占有互斥信号量的任务,若要释放掉互斥信号量,则必须执行与semTake同样次数的semGive操作。

计数信号量

与二进制信号量的不同

不同在于计数信号量可以用于记录信号量释放的次数,可以用来监视某一资源的使用情况。

状态

计数信号量用计数器代替了二进制信号量的二进制状态。当计数信号量被创建时,计数器被赋予一个初值,每次semTake或semGive时,计数器相应地减少或增加一个技术。当计数器小于0时,计数信号量状态变为不可用。

常用函数

  • semCCreate(int options , int initialCount):创建计数信号量,前一个参数同二进制信号量,后一个参数表示计数器的初始值。