Interprocess Communication

Table of Contents

1. IPC 简介

在进程之间交换信息的方法,称为 IPC(Interprocess Communication)。

IPC_summary.png

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 对象的影响

IPC_effect_of_calling_fork_exec.gif

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

IPC_System_V_functions.png

Figure 3: Summary of System V IPC functions

IPC_POSIX_functions.png

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名字”的移植性问题)

Author: cig01

Created: <2013-01-05 Sat>

Last updated: <2017-01-16 Mon>

Creator: Emacs 27.1 (Org mode 9.4)