Interprocess Communication
Table of Contents
1. IPC 简介
在进程之间交换信息的方法,称为 IPC(Interprocess Communication)。
Figure 1: Summary of UNIX System IPC
参考:
Advanced Programming in the UNIX Environment, 3rd Edition, Chapter 15 Interprocess Communication
UNIX 网络编程第 2 卷:进程间通信(第 2 版)
1.1. fork、exec 和 exit 对 IPC 对象的影响
Figure 2: 调用 fork、exec 和 exit 对 IPC 对象的影响
参考:UNIX 网络编程第 2 卷:进程间通信(第 2 版),1.5 节 fork、exec 和 exit 对 IPC 对象的影响
2. System V IPC vs. POSIX IPC
消息队列、信号量和共享内存是三种重要的 IPC 方式:
- Message queues can be used to pass messages (formatted data streams) between processes.
- Semaphores permit multiple processes to synchronize their actions.
- Shared memory enables multiple processes to share the same region (called a segment) of memory. Since access to user-space memory is a fast operation, shared memory is one of the quickest methods of IPC: once one process has updated the shared memory, the change is immediately visible to other processes sharing the same segment.
对于消息队列、信号量和共享内存这三种 IPC 方式,分别都有两套可用的设施:System V IPC 和 POSIX IPC。
System V IPC 是 20 世纪 70 年代后期在贝尔实验室一个称为“Columbus Unix”的内部版本中开发的,System V IPC 大约于 1983 年随 System V 加入到商业 Unix 系统中。由于 System V IPC 定义在 Single UNIX Specification 的 XSI 扩展中,所以 System V IPC 也被称作 XSI IPC 。
Figure 3: Summary of System V IPC functions
Figure 4: Summary of POSIX IPC functions
2.1. System V IPC 实例:Shared Memory
下面是 Shared Memory(System V IPC)的一个例子,有两个程序 shm_server 和 shm_client,一个写共享内存一个读共享内存。
源码如下:
/* shm_server: 往共享内存中写入27个字节:全部小写的英文字母加上NULL */ #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdio.h> #include <stdlib.h> #define SHMSZ 27 /* Size of shared memory */ #define IPCKEY 23456 /* Key of shared memory */ int main() { key_t key = IPCKEY; int shmid; /* Identifier of shared memory */ char *shm, *s; char c; /* Create the shared memory segment. */ if ((shmid = shmget(key, SHMSZ, IPC_CREAT | 0666)) < 0) { perror("shmget"); exit(1); } /* Attach the shared memory segment. */ if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) { perror("shmat"); exit(1); } s = shm; /* Write [abc...xyz] to shared memory. */ for (c = 'a'; c <= 'z'; c++) { *s++ = c; } *s = NULL; return 0; }
/* shm_client: 打印共享内存中的内容直到遇到NULL */ #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdio.h> #include <stdlib.h> #define IPCKEY 23456 /* Key of shared memory */ int main() { key_t key = IPCKEY; int shmid; char *shm, *s; /* Locate the shared memory segment. */ if ((shmid = shmget(key, 0, 0666)) < 0) { perror("shmget"); exit(1); } /* Attach the shared memory segment to our data space. */ if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) { perror("shmat"); exit(1); } /* Read memory util meet NULL. */ for (s = shm; *s != NULL; s++) { putchar(*s); } putchar('\n'); return 0; }
测试如下:
$ ./shm_server # shm_server仅是创建共享内存并写入内存,没有输出 $ ./shm_client abcdefghijklmnopqrstuvwxyz
说明:上面两个程序结束后,并没有删除共享内存,我们可以通过 ipcs 查看到 shm_server 创建的共享内存。如:
$ ipcs -m ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00061de2 513245204 root 666 28 0 0x435dce61 23560214 root 666 4 1 0x435dce60 23592983 root 666 8024 1 0x741cc1a0 48889886 root 666 28244 0 0x741cc1a1 48922655 root 666 6 0 0x741cc1a2 48955424 root 666 6 0 0x00005ba0 738689112 cig01 666 27 0
上面输出中,最后一条记录就是 shm_server 创建的共享内存(程序中指定的 key 为 23456,对应的十六进制为 0x00005ba0)。
2.2. System V IPC 和 POSIX IPC 的优缺点
POSIX IPC 有下面优点:
- POSIX IPC 的接口更加简单,使用起来更加方便。
- POSIX IPC 模型使用“POSIX IPC 名字”进行标识,使用 xx_open/xxx_close/xx_unlink 来操作它们,这和 UNIX 的文件模型更一致。
- POSIX IPC 对象是“引用计数”的,支持持续时间“随进程”的方式(没有进程访问它了就自动删除);而 System V IPC 没有访问计数,持续时间是“随内核”的,很可能出现由于用户疏忽或程序异常导致 IPC 资源一直没有释放。
System V IPC 的主要优点是它的可移植性更好 ,这体现在几个方面:
- 几乎所有的 UNIX 实现都支持 System V IPC,而 POSIX IPC 在老的或某些新的 UNIX 中可能没有实现。
- “POSIX IPC 名字”可能是真正的路径名,也可能不是,不同系统的实现可能不同,用 POSIX IPC 编写可移植的代码需要做额外的工作。而 System V IPC 没有这个问题。
参考:
The Linux Programming Interface, 51.2 Comparison of System V IPC and POSIX IPC
UNIX网络编程第2卷:进程间通信(第2版),2.2 IPC名字(讨论了关于“POSIX IPC名字”的移植性问题)