信号量
信号量(Semaphore)
又称为信号灯、旗语等,本质是一个无符号整形变量象,用于多线程之间同步或资源保护。
对信号量最核心的是两个操作pend(等待)和post(释放)。对一个信号量pend时,如果信号量大于0则获取信号量成功,信号量减一,正常退出后程序继续运行;如果为0,则要将当前线程挂起,直到其他线程释放信号量使得当前线程可以获取时才能被唤醒继续执行。对一个信号量post时,则会使得信号量加一,如果有阻塞线程因此可获得信号量,则可能会执行线程调度。
信号量有些像裸机程序里常用的标志(flag),标志就是个全局整形变量,也可以用于同步和资源保护。比如串口写完发送FIFO后,可以等一个发送完成标志,发送中断中检查到发送完成后就可以置位这个发送完成标志,此时发送函数中检查到发送完成标志就可以正常退出了。对于共同访问的资源,初始化为1,获取时置0用完再值1,这样若资源正在使用时,其他任务看到标志位0就要放弃。
信号量要比标志好用的多,首先它能保证原子操作避免同时获取或释放时出错,其次当获取失败时,可以让出CPU,进入阻塞状态,阻塞状态下的线程也可以因获取信号量而被唤醒,然后继续执行,保证整个调用过程同步实现。操作系统会包含一个等待信号量线程队列(用于存放等待信号量的线程),当信号量可以被获得时,操作系统依据某种策略从队列中选择一个可以获得信号量的线程以继续运行。
SylixOS里的信号量
SylixOS提供原生的信号量机制,其特点如下:
- 提供四种类型:二进制信号量、计数型信号量、互斥信号量和读写信号量。
- 支持两种等待唤醒类型:优先级等待和FIFO等待。
- 可以设置超时时间,时间单位是心跳周期,也可以是不等待或无限等待。
- 互斥信号量支持两种防止优先级翻转策略:优先级继承和优先级天花板。
- 可以设置为全局对象或局部对象,其中当进程退出时不会释放全局对象资源。
- 可以传递一个消息指针,起到传统RTOS中邮箱的作用,所以SylixOS没有提供邮箱的API。
SylixOS同时还提供POSIX标准的信号量,方便程序开发和移植,包括:
- 匿名信号量 sem_t
- 命名信号量 sem_t
- 互斥信号量 pthread_mutex_t
SylixOS里信号量的通用接口
SylixOS提供的4种原生的信号量都有各自接口,但有些接口很相似,所以还提供了一些通用信号量接口。再有就是4种原生的信号量会用到一些通用的属性配置,这些配置是个位域,通过宏来定义。
通用宏配置属性
/*********************************************************************************************************
等待时间 (超时选项)
*********************************************************************************************************/
#define LW_OPTION_NOT_WAIT 0x00000000 /* 不等待立即退出 */
#define LW_OPTION_WAIT_INFINITE __ARCH_ULONG_MAX/* 永远等待 */
#define LW_OPTION_WAIT_A_TICK 0x00000001 /* 等待一个时钟嘀嗒 */
#define LW_OPTION_WAIT_A_SECOND CLOCKS_PER_SEC/* 等待一秒 */
/*********************************************************************************************************
等待排序算法 (创建选项)
*********************************************************************************************************/
#define LW_OPTION_WAIT_PRIORITY 0x00010000 /* 按优先级顺序等待 */
#define LW_OPTION_WAIT_FIFO 0x00000000 /* 按先进先出顺序等待 */
/*********************************************************************************************************
删除安全 (创建选项)
*********************************************************************************************************/
#define LW_OPTION_DELETE_SAFE 0x00020000 /* Mutex or RW 安全删除使能 */
#define LW_OPTION_DELETE_UNSAFE 0x00000000 /* Mutex or RW 非安全保护使能 */
/*********************************************************************************************************
等待过程中遇到信号处理方式 (创建选项) (同样适用于 EVENTSET)
*********************************************************************************************************/
#define LW_OPTION_SIGNAL_INTER 0x00040000 /* 可被信号打断 (EINTR) */
#define LW_OPTION_SIGNAL_UNINTER 0x00000000 /* 不可被信号打断 */
/*********************************************************************************************************
互斥信号量优先级算 (创建选项)
*********************************************************************************************************/
#define LW_OPTION_INHERIT_PRIORITY 0x00080000 /* 优先级继承算法 */
#define LW_OPTION_PRIORITY_CEILING 0x00000000 /* 优先级天花板算法 */
/*********************************************************************************************************
互斥信号量, 读写锁是否允许重入 (创建选项)
*********************************************************************************************************/
#define LW_OPTION_NORMAL 0x00100000 /* 递归时不检查 (不推荐) */
#define LW_OPTION_ERRORCHECK 0x00200000 /* Mutex or RW 递归时报错 */
#define LW_OPTION_RECURSIVE 0x00000000 /* Mutex or RW 支持写递归调用 */
/*********************************************************************************************************
读写锁读写优先控制 (创建选项)
*********************************************************************************************************/
#define LW_OPTION_RW_PREFER_READER 0x00000000 /* 读访问优先 */
#define LW_OPTION_RW_PREFER_WRITER 0x00400000 /* 写访问优先 */
注意:
LW_OPTION_WAIT_PRIORITY和LW_OPTION_WAIT_FIFO只能二选一。LW_OPTION_OBJECT_GLOBAL和LW_OPTION_OBJECT_LOCAL只能二选一。
通用信号量API接口
/*********************************************************************************************************
** 函数名称: API_SemaphorePend
** 功能描述: 等待信号量
** 输 入 :
** ulId 事件句柄
** ulTimeout 等待时间
** 输 出 :
*********************************************************************************************************/
LW_API
ULONG API_SemaphorePend (LW_OBJECT_HANDLE ulId, ULONG ulTimeout)
/*********************************************************************************************************
** 函数名称: API_SemaphorePost
** 功能描述: 释放信号量
** 输 入 :
** ulId 事件句柄
** 输 出 :
*********************************************************************************************************/
LW_API
ULONG API_SemaphorePost (LW_OBJECT_HANDLE ulId)
/*********************************************************************************************************
** 函数名称: API_SemaphoreFlush
** 功能描述: 释放等待信号量的所有线程
** 输 入 :
** ulId 事件句柄
** pulThreadUnblockNum 被解锁的线程数量 可以为NULL
** 输 出 :
*********************************************************************************************************/
LW_API
ULONG API_SemaphoreFlush (LW_OBJECT_HANDLE ulId, ULONG *pulThreadUnblockNum)
/*********************************************************************************************************
** 函数名称: API_SemaphoreDelete
** 功能描述: 删除信号量
** 输 入 :
** pulId 事件句柄
** 输 出 :
*********************************************************************************************************/
LW_API
ULONG API_SemaphoreDelete (LW_OBJECT_HANDLE *pulId)
/*********************************************************************************************************
** 函数名称: API_SemaphorePostBPend
** 功能描述: 释放一个信号量后立即开始等待另外一个信号量(中间无任务切换发生)
** 输 入 : ulIdPost 需要释放的信号量
** ulId 需要等待的信号量 (二值信号量)
** ulTimeout 等待超时时间
** 输 出 :
*********************************************************************************************************/
LW_API
ULONG API_SemaphorePostBPend (LW_OBJECT_HANDLE ulIdPost,
LW_OBJECT_HANDLE ulId,
ULONG ulTimeout)
/*********************************************************************************************************
** 函数名称: API_SemaphorePostCPend
** 功能描述: 释放一个信号量后立即开始等待另外一个信号量(中间无任务切换发生)
** 输 入 : ulIdPost 需要释放的信号量
** ulId 需要等待的信号量 (计数信号量)
** ulTimeout 等待超时时间
** 输 出 :
*********************************************************************************************************/
LW_API
ULONG API_SemaphorePostCPend (LW_OBJECT_HANDLE ulIdPost,
LW_OBJECT_HANDLE ulId,
ULONG ulTimeout)
另外,系统通过宏定义还为这些接口定义了一些别名,如下:
#define Lw_Semaphore_Wait API_SemaphorePend
#define Lw_Semaphore_Get API_SemaphorePend
#define Lw_Semaphore_Take API_SemaphorePend
#define Lw_Semaphore_Post API_SemaphorePost
#define Lw_Semaphore_Give API_SemaphorePost
#define Lw_Semaphore_Send API_SemaphorePost
#define Lw_Semaphore_Flush API_SemaphoreFlush
#define Lw_Semaphore_Delete API_SemaphoreDelete
#define Lw_Semaphore_PostBPend API_SemaphorePostBPend
#define Lw_Semaphore_PostCPend API_SemaphorePostCPend