Linux信号量(2)-POSIX 信号量

上一章 , 讲述了SYSTEM V信号量 , 主要运行于进程之间 , 本章主要介绍POSIX信号量:有名信号量、无名信号量 。
Linux信号量(2)-POSIX 信号量文章插图
POSIX信号量POSIX信号量进程是3种 IPC(Inter-Process Communication) 机制之一 , 3种 IPC 机制源于 POSIX.1 的实时扩展 。 Single UNIX Specification 将3种机制(消息队列 , 信号量和共享存储)置于可选部分中 。 在 SUSv4 之前 , POSIX 信号量接口已经被包含在信号量选项中 。 在 SUSv4 中 , 这些接口被移至了基本规范 , 而消息队列和共享存储接口依然是可选的 。
POSIX 信号量接口意在解决 XSI 信号量接口的几个缺陷 。

  1. 相比于 XSI 接口 , POSIX 信号量接口考虑了更高性能的实现 。
  2. POSIX 信号量使用更简单:没有信号量集 , 在熟悉的文件系统操作后一些接口被模式化了 。 尽管没有要求一定要在文件系统中实现 , 但是一些系统的确是这么实现的 。
  3. POSIX 信号量在删除时表现更完美 。 回忆一下 , 当一个 XSI 信号量被删除时 , 使用这个信号量标识符的操作会失败 , 并将 errno 设置成 EIDRM 。 使用 POSIX 信号量时 , 操作能继续正常工作直到该信号量的最后一次引用被释放 。
分类POSIX信号量是一个sem_t类型的变量 , 但POSIX有两种信号量的实现机制:无名信号量和命名信号量 。 无名信号量只可以在共享内存的情况下 , 比如实现进程中各个线程之间的互斥和同步 , 因此无名信号量也被称作基于内存的信号量;命名信号量通常用于不共享内存的情况下 , 比如进程间通信 。
同时 , 在创建信号量时 , 根据信号量取值的不同 , POSIX信号量还可以分为:
  • 二值信号量:信号量的值只有0和1 , 这和互斥量很类似 , 若资源被锁住 , 信号量的值为0 , 若资源可用 , 则信号量的值为1;
  • 计数信号量:信号量的值在0到一个大于1的限制值之间 , 该计数表示可用的资源的个数 。
区别有名信号量和无名信号量的差异在于创建和销毁的形式上 , 但是其他工作一样 。
无名信号量只能存在于内存中 , 要求使用信号量的进程必须能访问信号量所在的这一块内存 , 所以无名信号量只能应用在同一进程内的线程之间(共享进程的内存) , 或者不同进程中已经映射相同内存内容到它们的地址空间中的线程(即信号量所在内存被通信的进程共享) 。 意思是说无名信号量只能通过共享内存访问 。
相反 , 有名信号量可以通过名字访问 , 因此可以被任何知道它们名字的进程中的线程使用 。
单个进程中使用 POSIX 信号量时 , 无名信号量更简单 。 多个进程间使用 POSIX 信号量时 , 有名信号量更简单 。
联系无论是有名信号量还是无名信号量 , 都可以通过以下函数进行信号量值操作 。
wait(P)wait 为信号量值减一操作 , 总共有三个函数 , 函数原型如下:
#include int sem_wait(sem_t *sem);int sem_trywait(sem_t *sem);int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);Link with -pthread.这一句表示 gcc 编译时 , 要加 -pthread.返回值:若成功 , 返回 0 ;若出错 , 返回-1
  • sem_wait的作用是 , 若 sem 小于 0, 则线程阻塞于信号量 sem, 直到 sem 大于 0 ;否则信号量值减1 。
  • sem_trywait作用与sem_wait相同 , 只是此函数不阻塞线程 , 如果 sem 小于 0 , 直接返回一个错误(错误设置为 EAGAIN ) 。
  • sem_timedwait作用也与sem_wait相同 , 第二个参数表示阻塞时间 , 如果 sem 小于 0, 则会阻塞 , 参数指定阻塞时间长度 。 abs_timeout 指向一个结构体 , 这个结构体由从 1970-01-01 00:00:00 +0000 (UTC) 开始的秒数和纳秒数构成 。
结构体定义如下:
struct timespec {time_t tv_sec;/* Seconds */longtv_nsec;/* Nanoseconds [0 .. 999999999] */}; 如果指定的阻塞时间到了 , 但是 sem 仍然小于 0, 则会返回一个错误 (错误设置为 ETIMEDOUT ) 。
post(V)post 为信号量值加一操作 , 函数原型如下:
#include int sem_post(sem_t *sem);Link with -pthread.返回值:若成功 , 返回 0 ;若出错 , 返回-1无名信号量接口函数信号量的函数都以sem_开头 , 线程中使用的基本信号函数有4个 , 他们都声明在头文件semaphore.h中 , 该头文件定义了用于信号量操作的sem_t类型:
sem_init
该函数用于创建信号量 , 原型如下:
int sem_init(sem_t *sem, int pshared, unsigned int value);功能:该函数初始化由sem指向的信号对象 , 设置它的共享选项 , 并给它一个初始的整数值 。 pshared控制信号量的类型 , 如果其值为0 , 就表示信号量是当前进程的局部信号量 , 否则信号量就可以在多个进程间共享 , value为sem的初始值 。 返回值:该函数调用成功返回0 , 失败返回-1 。