VxWorks为保证各个独立的任务可以协同工作,提供了一整套任务的通信机制,包括信号量、共享内存、消息队列、管道、信号、事件等,此外还有一些网络编程机制如套接字。本文主要对信号量进行总结介绍。
信号量简介
- 定义:信号量是实现任务互斥、同步操作的主要机制。在各种任务间通信机制中,速度最快。
- 功能:
- 互斥:不同任务可以利用信号量互斥地访问临界资源。这种互斥的访问方式比中断禁止与优先级锁定两种互斥方式更精确。
- 同步:一个任务可以利用信号量控制自己的执行进度,使自己同步于一组外部事件。
- 种类:
- 二进制信号量:完成互斥、同步操作的最佳方式,速度最快,最常用。
- 互斥信号量:特殊的二进制信号量,专门针对互斥操作进行优化。新特性有优先级继承、删除保护与递归访问。
- 技术信号量:类似于二进制信号量,可记录信号量释放的次数,可监视统一资源的多个实例。
- 控制接口:
semBCreate()
:创建二进制信号量semMCreate()
:创建互斥信号量semCCreate()
:创建计数信号量semDelete()
:删除并释放信号量semTake()
:获取一个信号量semGive()
:释放一个信号量semFlush()
:将所有等待该信号量的任务唤醒
二进制信号量
状态
二进制信号量有两种状态,分别为SEM_FULL
和SEM_EMPTY
,前者表示信号量可用,后者表示信号量不可用
常用函数
semBCreate(int option, SEM_B_STATS initialState)
:创建信号量。前一个参数决定任务在二进制信号量上的排队方式,可选SEM_Q_PRIORITY
和SEM_Q_FIFO
。后一个参数决定信号量的初始状态,可选SEM_FULL
和SEM_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):创建计数信号量,前一个参数同二进制信号量,后一个参数表示计数器的初始值。