Following table lists the differences between System V IPC and POSIX IPC[^2].
SYSTEM V
POSIX
AT & T introduced (1983) three new forms of IPC facilities namely message queues, shared memory, and semaphores.
Portable Operating System Interface standards specified by IEEE to define application programming interface (API). POSIX covers all the three forms of IPC
SYSTEM V IPC covers all the IPC mechanisms viz., pipes, named pipes, message queues, signals, semaphores, and shared memory. It also covers socket and Unix Domain sockets.
Almost all the basic concepts are the same as System V. It only differs with the interface
Semaphore Interface Calls Named Semaphores sem_open(), sem_close(), sem_unlink(), sem_post(), sem_wait(), sem_trywait(), sem_timedwait(), sem_getvalue() Unnamed or Memory based semaphores sem_init(), sem_post(), sem_wait(), sem_getvalue(),sem_destroy()
Uses keys and identifiers to identify the IPC objects.
Uses names and file descriptors to identify IPC objects
NA
POSIX Message Queues can be monitored using select(), poll() and epoll APIs
Offers msgctl() call
Provides functions (mq_getattr() and mq_setattr()) either to access or set attributes 11. IPC - System V & POSIX
NA
Multi-thread safe. Covers thread synchronization functions such as mutex locks, conditional variables, read-write locks, etc.
NA
Offers few notification features for message queues (such as mq_notify())
Requires system calls such as shmctl(), commands (ipcs, ipcrm) to perform status/control operations.
Shared memory objects can be examined and manipulated using system calls such as fstat(), fchmod()
The size of a System V shared memory segment is fixed at the time of creation (via shmget())
We can use ftruncate() to adjust the size of the underlying object, and then re-create the mapping using munmap() and mmap() (or the Linux-specific mremap())
上面是摘录的,下面谈下我的理解:我们在Linux编程里面,关于线程可以使用pthread_mutex, spinlock这些工具,这些工具都是在一个进程中的,守护的是进程内部的资源,因此作者提到随进程持续的概念;而两个无关进程之间对于访问同一个资源,比如文件,也是可能会有临界区,只是相比于进程内部的临界区,扩展到了系统内部的临界区,因此这里有随内核持续的概念。这也是为什么POSIX是一个轻量级的常用于线程的,而System V IPC是一个深陷内核的常用于进程的标准。我相信IPC在进程层级和线程层级既有相似的点也有不同的点。
System V中提供的信号量接口更通用相比于POSIX标准的信号量[^15]。我们从后面的API介绍上面可以看出,system V中的提供的信号量接口是非常复杂和繁琐的,虽然接口少,但是标识符,标志位特别多,而且里面定义了很多自己的结构体的结构,甚至出现了变长参数。根据文献[^15],我们大分部使用的都是二进制的信号量,但我相信,这些接口都不是白给的,肯定有更多的使用场景,可能需要以后工作情景上面进行挖掘了。
2.1 APIs
2.1.1 semctl[^16]
semctl() performs the control operation specified by cmd on the System V semaphore set identified by semid, or on the semnum-th semaphore of that set. (The semaphores in a set are numbered starting at 0.)
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, ...);
The semget() system call returns the System V semaphore set identifier associated with the argument key. It may be used either to obtain the identifier of a previously created semaphore set (when semflg is zero and key does not have the value IPC_PRIVATE), or to create a new set.
A new set of nsems semaphores is created if key has the value IPC_PRIVATE or if no existing semaphore set is associated with key and IPC_CREAT is specified in semflg.
If semflg specifies both IPC_CREAT and IPC_EXCL and a semaphore set already exists for key, then semget() fails with errno set to EEXIST. (This is analogous to the effect of the combination O_CREAT | O_EXCL for open(2).)
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
semop() performs operations on selected semaphores in the set indicated by semid. Each of the nsops elements in the array pointed to by sops is a structure that specifies an operation to be performed on a single semaphore. The elements of this structure are of type struct sembuf, containing the following members:
#include <sys/sem.h>
struct sembuf {
unsigned short sem_num; /* semaphore number */
short sem_op; /* semaphore operation */
short sem_flg; /* operation flags */
};
int semop(int semid, struct sembuf *sops, size_t nsops);
int semtimedop(int semid, struct sembuf *sops, size_t nsops,
const struct timespec *timeout); // _GNU_SOURCE
Linux进程之间的通信-信号量(System V and POSIX IPC)
IPC(Inter-Process Communication,进程间通讯)包含三种通信方式,信号量、共享内存和消息队列。在linux编程里面可以有两个不同的标准,一个是SYSTEM-V标准,一个是POSIX标准。以下是两个标准之间的区别[^1]。简单的说,POSIX更轻量,常面向于线程;SYSTEM-V更重一些,需要深陷Linux内核之中,面向于进程。
1. POSIX和SYSTEM-V的区别
Following table lists the differences between System V IPC and POSIX IPC[^2].
我从文献里面得到几个进程持续性概念,我觉得这个角度分类比较好。直接抄文献:从IPC的持续性角度而言,可以把进程通信分为以下几类[^3]:
上面是摘录的,下面谈下我的理解:我们在Linux编程里面,关于线程可以使用pthread_mutex, spinlock这些工具,这些工具都是在一个进程中的,守护的是进程内部的资源,因此作者提到随进程持续的概念;而两个无关进程之间对于访问同一个资源,比如文件,也是可能会有临界区,只是相比于进程内部的临界区,扩展到了系统内部的临界区,因此这里有随内核持续的概念。这也是为什么POSIX是一个轻量级的常用于线程的,而System V IPC是一个深陷内核的常用于进程的标准。我相信IPC在进程层级和线程层级既有相似的点也有不同的点。
2. 信号量
在Linux-用户空间-多线程与同步^14中,引用了sem_xxx()的接口,根据上面的信息我们也可以知道这是POSIX IPC的接口。我们在那个文章中并没有阐述信号量和spinlock的区别,在网上大多数人只谈论到信号量和锁之间的用法上的区别,或者是意义上的区别。我这里想更进一步的解释信号量的实现和锁是有差别的。还有pthread_xxx里面的spinlock和内核的spinlock理念是一样的,但是调度完全不一样,pthread_xxx的可以关注这个实验^14。
System V中提供的信号量接口更通用相比于POSIX标准的信号量[^15]。我们从后面的API介绍上面可以看出,system V中的提供的信号量接口是非常复杂和繁琐的,虽然接口少,但是标识符,标志位特别多,而且里面定义了很多自己的结构体的结构,甚至出现了变长参数。根据文献[^15],我们大分部使用的都是二进制的信号量,但我相信,这些接口都不是白给的,肯定有更多的使用场景,可能需要以后工作情景上面进行挖掘了。
2.1 APIs
2.1.1 semctl[^16]
Parameters:
Return:
根据cmd不同,返回值也不同。对于 SETVAL和IPC_RMID而言,成功时返回0,失败时返回-1。
2.1.2 semget[^17]
创建一个新的信号量或取得一个已有的信号量的key。
Parameters:
Return:
返回非零整数,为semctl,semop的标识符,返回<0失败。
2.1.3 semop[^18]
改变信号量的值。
Parameters:
Return:
2.2 Example
根据文献[^15]提供的示例,完成使用System V级别的信号量,创建简单的二进制信号量,满足以下条件:
关于semun.h请参考https://man7.org/tlpi/code/online/dist/svsem/semun.h.html, MACOS里面自带了定义,但是在Ubuntu和ARM-Linux上面并没有这个定义。
这里还要说一下,因为是使用的系统上的资源竞争(同一个文件),因此必须使用System V级别的信号量才能完成,而posix提供的同步的信号量的内存都是存在一个进程里面的。
这个例子划分 写入文件十次为一个临界区。
$ rm -rf common.txt
$ ./test_sem.elf 1
$ ./test_sem.elf
Reference
[^1]: System V IPC vs POSIX IPC - Stack Overflow [^2]:System V & Posix (tutorialspoint.com) [^3]:UNIX 进程间通讯(IPC)概念(Posix,System V IPC) [^4]:临界区互斥实现:Dekker互斥算法 - 知乎 (zhihu.com)
[^6]:如何更好理解Peterson算法? - 知乎 (zhihu.com) [^7]: Peterson算法 - 维基百科,自由的百科全书 (wikipedia.org) [^8]: Szymanski算法 - 维基百科,自由的百科全书 (wikipedia.org) [^9]: Lamport面包店算法 - 维基百科,自由的百科全书 (wikipedia.org) [^10]: 一文搞懂 | Linux 同步管理(上) [^11]: ARM WFI和WFE指令 [^12]:06_ARMv8_指令集_一些重要的指令 · Issue #12 · carloscn/blog (github.com)
[^15]:[Linux系统编程(第四版)- page490]() [^16]:archlinux man page - semctl ↩ [^17]:archlinux man page - semget ↩ [^18]:archlinux man page - semop ↩