一、概念

APUE编程:130---进程间通信(信号量:sem)_POSIX之信号量

二、POSIX信号量接口与XSI信号量接口的区别

POSIX信号量接口解决了XSI信号量接口的一下几个缺陷:

  • 相比于XSI接口,POSIX信号量接口提高了性能
  • POSIX信号量接口使用更简单:没有信号量集合的概念
  • POSIX信号量在删除时表现更完美:XSI信号量被删除时,使用这个信号量标识符的操作会失败,并将errno设置为WIDRM。但是使用POSIX信号量时,操作能继续正常工作直到该信号量的最后一次引用被释放
三、POSIX信号量的形式

POSIX信号量有两种形式:命名的和未命名的。它们的差异在于创建和销毁的形式上,但其它工作一样。

  • 未命名信号量:只存在内存中,并要求能使用信号量的进程必须可以访问内存。所有这些信号量能应用在同一进程中的线程,或者不同进程中已经映射相同内存内容都它们的地址空间中的线程

  • 命名信号量:可以通过名字访问,因此可以被任何已知它们名字的进程中的线程使用
四、命名信号量的创建(sem_open)
#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <semaphore.h>
sem_t *sem_open(const char *name, int oflag,/*mode_t mode, unsigned int value*/);
  • 功能:用来创建一个新的命名信号量或者使用一个现有的信号量
  • 返回值:此函数会返回一个信号量指针,用于传递到其他信号量函数上来对信号量进行操作

此函数被用来创建一个新的信号量时,参数如下:

  • name:信号量的名字
  • oflag:使用O_CREAT(如果信号量已经存在,则O_CREAT什么都不做函数也不出错)。如果使用O_CREAT|O_EXCL(表示如果信号量已存在,则创建失败,sem_open函数出错返回)
  • mode:表示谁可以访问信号量。mode的取值如下:(赋值给信号量的权限可以被调用者的文件创建屏蔽字函数umask修改)。注意,只有读和写访问要紧,但是当我们打开一个现有信号量时接口不允许指定模式。实现经常为读和写打开信号量

APUE编程:130---进程间通信(信号量:sem)_可移植性_02

  • value:指定信号量的初始值。取值范围是0~SEM_VALUE_MAX

此函数被用来引用一个已存在的命名信号量时,参数如下:

  • name:信号量的名字
  • oflag:设置为0
  • mode、value:这两个参数不填

信号量名的命名规则:

  • 为了增加可移植性,要遵循以下规则

APUE编程:130---进程间通信(信号量:sem)_可移植性_03

五、命名信号量的释放(sem_close)
#include <semaphore.h>
int sem_close(sem_t *sem);

//返回值:成功返回0;失败返回-1
  • 功能:用来释放信号量相关的资源。释放并不等于销毁(sem_unlink)

注意事项:

  • 如果进程没有调用sem_close而退出,那么内核将自动关闭任何打开的信号量。但是,这不会影响信号量的状态---如果已经对它进行了增1操作,这并不会仅因为退出而改变
  • 如果调用sem_close,信号量值也不会受到影响
  • 在POSIX信号量中没有XSI信号量机制的SEM_UNDO标志的机制
六、命名信号量的销毁(sem_unlink)
#include <semaphore.h>
int sem_unlink(const char *name);

//返回值:成功返回0;失败返回-1
  • 功能:来销毁一个命名的信号量。根据信号量的名字来删除(参数为要删除的信号量的名字)

注意事项:

  • 销毁时,如果信号量没有被引用,则立即销毁
  • 如果信号量正在被引用/使用,则销毁信号量的操作会延迟到最后一个打开的引用被关闭
七、命名信号量的值的增加与减少

APUE编程:130---进程间通信(信号量:sem)_#include_04

#include <semaphore.h>
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

//返回值:成功返回0;出错返回-1
  • 功能:都是对指定信号量的值进行减1操作 

sem_wait函数:

  • 如果信号量计数是0就会发生阻塞。直到成功使信号量减1(例如其它操作使信号量值被加1了,此函数立即减1)或者被信号中断时才返回

sem_trywait函数:

  • 此函数不阻塞。如果信号量的值是0(没值可减),则函数直接出错返回-1,并设置errno为EAGAIN

sem_timewait函数:

  • 可以用参数来指定减1操作的等待时间。超时是基于CLOCK_REALTIME时钟的
  • 如果在等待的时间内,信号量值成功减1,那么函数就成功返回
  • 如果超时信号量值还没有减1,则函数返回-1,并将errno设置为ETIMEDOUT
#include <semaphore.h>
int sem_post(sem_t *sem);

//返回值:成功返回0;出错返回-1
  • 功能:此函数使信号量值增1。这和解锁一个二进制信号量或者释放一个计数信号量相关的资源的过程是类似的

注意事项:

  • 调用sem_post时,如果在调用sem_wait或者sem_timewait中发生进程阻塞,那么进程会被唤醒并且被sem_post增1的信号量计数会被再次被sem_wait或者sem_timewait减1