免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4272 | 回复: 8
打印 上一主题 下一主题

父子进程间 IPC 总结 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2005-11-30 02:32 |只看该作者 |倒序浏览
目前小弟熟悉的、特定适用于父子进程之间的 IPC 方式有三种:pipe、匿名 FIFO(Unix domain socket)和共享内存。Named pipe, named FIFO, socket 和 SysV SHM 等因为都具有全局名称 / URI,适用于不相关的进程;而这里提到的三种 IPC,只适用于父子进程。

1、管道

Pipe 的特点:单向传递。在管道创建的时候,数据只能从读处读,从写处写,属于单向流动。相关文章已经太多了,小弟不多废话,贴一段代码提示记忆。

  1. $ cat -n pipe.c
  2.      1  #include <unistd.h>
  3.      2  #include <assert.h>
  4.      3
  5.      4  int main ()
  6.      5  {
  7.      6    int fd[2];
  8.      7    #define READER 0
  9.      8    #define WRITER 1
  10.      9
  11.     10    int r = pipe( fd );
  12.     11    if ( r != 0 ) {
  13.     12      perror( "pipe()" );
  14.     13      exit( 1 );
  15.     14    }
  16.     15
  17.     16    if ( fork() ) {
  18.     17      /* Parent, writer */
  19.     18      int n = 0;
  20.     19      close( fd[READER] );
  21.     20      while ( 1 ) {
  22.     21        ++n;
  23.     22        write( fd[WRITER], &n, sizeof(n) );
  24.     23        sleep( 1 );
  25.     24      }
  26.     25    }
  27.     26    else {
  28.     27      /* Child, reader */
  29.     28      int n;
  30.     29      close( fd[WRITER] );
  31.     30      while ( 1 ) {
  32.     31        read( fd[READER], &n, sizeof(n) );
  33.     32        printf( "Got value: %d\n", n );
  34.     33      }
  35.     34    }
  36.     35  }
复制代码

因为 pipe 只能进行单向传递的特性,popen(3) 的第二个参数只能为读写之一种,就是这个道理了。

2、socketpair
基本类似 pipe,不过是基于 Unix domain socket,通信为双向通信。

  1. $ cat -n socketpair.c
  2.      1  #include <sys/types.h>
  3.      2  #include <sys/socket.h>
  4.      3
  5.      4  #include <stdlib.h>
  6.      5  #include <stdio.h>
  7.      6
  8.      7  int main ()
  9.      8  {
  10.      9    int fd[2];
  11.     10
  12.     11    int r = socketpair( AF_UNIX, SOCK_STREAM, 0, fd );
  13.     12    if ( r < 0 ) {
  14.     13      perror( "socketpair()" );
  15.     14      exit( 1 );
  16.     15    }
  17.     16
  18.     17    if ( fork() ) {
  19.     18      /* Parent process: echo client */
  20.     19      int val = 0;
  21.     20      close( fd[1] );
  22.     21      while ( 1 ) {
  23.     22        sleep( 1 );
  24.     23        ++val;
  25.     24        printf( "Sending data: %d\n", val );
  26.     25        write( fd[0], &val, sizeof(val) );
  27.     26        read( fd[0], &val, sizeof(val) );
  28.     27        printf( "Data received: %d\n", val );
  29.     28      }
  30.     29    }
  31.     30    else {
  32.     31      /* Child process: echo server */
  33.     32      int val;
  34.     33      close( fd[0] );
  35.     34      while ( 1 ) {
  36.     35        read( fd[1], &val, sizeof(val) );
  37.     36        ++val;
  38.     37        write( fd[1], &val, sizeof(val) );
  39.     38      }
  40.     39    }
  41.     40  }
复制代码

Linux 系统中,socketpair 的第一个参数只能是 AF_LOCAL / AF_UNIX。

3、共享内存
传统 SysV IPC 系列提供了 Shared Memory 实现,简称 sysv shm。它的优劣在 Stevens 前辈的 APUE 中都有了详细介绍,此处不多做赘述。Linux 2.4 及之后版本的内核提供了一种新的进程间共享内存方式:通过 mmap。指定 MAP_SHARED | MAP_ANONYMOUS,系统会创建一块可被子进程继承的共享匿名内存块。它的优点是:与其它 mmap 分配的内存具有相同属性:当附着进程执行 exec 或者退出的时候,内存会被系统自动收回,而不像 sysv shm 一样仍然被保留在系统中。而且,由于不需要 key 来进行标识,它的 API 也相对更简单清晰。直接看代码好了。

  1. $ cat -n mmap.c
  2.      1  #include <stdlib.h>
  3.      2  #include <stdio.h>
  4.      3
  5.      4  #include <sys/mman.h>
  6.      5
  7.      6  int main ()
  8.      7  {
  9.      8    int *p = mmap( NULL, sizeof(int),
  10.      9                   PROT_READ|PROT_WRITE,
  11.     10                   MAP_SHARED|MAP_ANONYMOUS, // 关键在这里。
  12.     11                   0, 0 );
  13.     12    if ( p == MAP_FAILED ) {
  14.     13      perror( "mmap()" );
  15.     14      exit( 1 );
  16.     15    }
  17.     16
  18.     17    if ( fork() ) {
  19.     18      while ( 1 ) {
  20.     19        sleep( 1 );
  21.     20        printf( "Current val: %d\n", *p );
  22.     21        fflush(NULL);
  23.     22      }
  24.     23    }
  25.     24    else {
  26.     25      while ( 1 ) {
  27.     26        (*p)++;
  28.     27        sleep( 1 );
  29.     28      }
  30.     29    }
  31.     30  }
复制代码

相比较之前两种方式,共享内存有许多不同。首先,它不是通过文件描述符进行标识,而是直接将虚拟页面映射到进程内存空间中;传递数据也不需要在用户空间 <-> 核心的三块 buf 之间来回传递;其次,当执行 exec 之后,进程空间被全部重新生成,mmap 会自动脱离被映射的地址而不会继续继承;第三,与 sysvshm 一样,使用过程需要其它的同步手段,而 pipe / socket 自身提供了同步机制。

以上是小弟的一点学习心得,欢迎指正。

ps. 忽然想起前一段时间看到的 Win32 API 中 CreateFileMapping 如果指定第一个参数(文件句柄) hFile 为 INVALID_HANDLE_VALUE,则会在系统内存交换文件中创建一块映射区域。这大约是 Win32 在放弃了 SysV shm 之后的取代方案吧。

论坛徽章:
0
2 [报告]
发表于 2005-11-30 08:44 |只看该作者
支持!

论坛徽章:
0
3 [报告]
发表于 2005-11-30 08:44 |只看该作者
顶!!!

论坛徽章:
0
4 [报告]
发表于 2006-11-29 10:41 |只看该作者
用socketpair的话,父子进程随便从fd[1],fd[0]挑一个就行了吧,可以父进程用fd[0],子进程用fd[1],或者2者对换一下。

论坛徽章:
0
5 [报告]
发表于 2006-12-22 10:49 |只看该作者
楼主:
你能不能给一个共享内存和信号灯一起作用于进程通信同步的例子!

论坛徽章:
0
6 [报告]
发表于 2007-06-11 00:20 |只看该作者

有错

应该是:
int *p = mmap( NULL, sizeof(int),
     9                   PROT_READ|PROT_WRITE,
    10                   MAP_SHARED|MAP_ANON, // 关键在这里。
    11                   -1, 0 );
我用这种方式多个父子进程共享流水号,用了sem_init信号亮。已经上生产,没有出现问题

论坛徽章:
0
7 [报告]
发表于 2007-07-04 16:31 |只看该作者
哈哈

论坛徽章:
0
8 [报告]
发表于 2007-07-04 16:51 |只看该作者
差信号灯SYSV共享内存处理

论坛徽章:
0
9 [报告]
发表于 2007-07-12 13:19 |只看该作者
消息队列形式没有
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP