Linux下的进程通信方式之POSIX-信号量
Linux下的通信方式之 POSIX 信号量
前言
POSIX 中的信号量和 System 中的信号量不同点在于:
- System 其实是信号量集,而不是单纯的信号量。
- POSIX 中的信号量有两种,一种称为命名信号量,一种称为未命令信号量。这两个东⻄的唯⼀区别就是多个进程如何找到该信号量⽽已
命名信号量:不相关的进程通过这个名字能够访问同一个信号量。
未命名信号量:没有名字,位于内存中一个约定的位置,可以在进程之间或一组线程之间共享。进程间共享中,需要位于一个共享内存区域中。
命令信号量
前面提到,不相关的进程可以通过名字访问同一个信号量,这就是命名信号量。
命令信号量的创建和使用方式如下:
创建命令信号量
1 |
|
SUSv3 规定只能在原始返回的 sem_t 指针上操作,其副本操作是未定义的,即不能:
1 |
|
注意点
- 信号量的名字必须以斜杠开头,如 /myobject。但是不可以
//
两个斜杠开头,如//myobject
。 - 信号量的名字必须唯一,不能与其他信号量的名字相同。
- 信号量的名字长度不能超过 NAME_MAX。
关闭命令信号量
注意,关闭命名信号量和删除命名信号量不是同一个操作。
1 |
|
当一个进程打开一个命名信号量时,系统会记录进程与信号量之间的关联关系。sem_close 会终止这种关联关系(即关闭信号量),释放系统为该进程关联到该信号量之上的所有资源,并递减引用该信号量的进程数。 在进程终止或者调用了 exec 时,会被自动关闭,关闭信号量并不代表删除信号量。
删除命令信号量
1 |
|
命令信号量操作
等待命令信号量
这个操作有两个函数,一个是 sem_wait,另一个是 sem_trywait。
这两者的区别在于,前者是阻塞版本,后者是非阻塞版本。
1 |
|
如果一个阻塞的 sem_wait 调用被一个信号处理器中断了,那么它就会失败并返回 EINTR 错误,不管在使用 sigaction 建立这个信号处理器时是否采用了 SA_RESTART 标记。 非阻塞版本:
1 |
|
发布一个信号量
1 |
|
获取信号量当前值
1 |
|
未命名信号量
未命名信号量的操作与信号量是一样的,它的创建与删除会用到额外的两个函数,这两个函数不应该用在命名信号量上。 在线程间共享的信号量不需要名字。在相关进程间共享的信号量不需要名字。如果一个父进程在一块共享内存区域中(如一个共享匿名映射)分配了一个未命名信号量,那么作为 fork 操作的一部分,子进程会自动继承这个映射,从而继承这个信号量。
初始化一个未命名信号量
1 |
|
删除一个未命名信号量
1 |
|
信号量限制
下面限制定义在 limits.h 中:
1 |
|
总结
- System V的信号量一般用于进程同步, 且是内核持续的, api为:semget、semctl、semop
- Posix的有名信号量一般用于进程同步, 有名信号量是内核持续的. 有名信号量的api为:sem_open、sem_close、sem_unlink
- Posix的无名信号量一般用于线程同步, 无名信号量是进程持续的, 无名信号量的api为:sem_init、sem_destroy