父子进程间 IPC 总结
来源:互联网 发布:电脑w8软件下载 编辑:程序博客网 时间:2024/06/11 11:38
目前本人熟悉的、特定适用于父子进程之间的 IPC 方式有三种:pipe、匿名 FIFO(Unix domain socket)和共享内存。现在将使用方法总结一下。
1、管道
Pipe 的特点:单向传递。在管道创建的时候,数据只能从读处读,从写处写,属于单向流动。相关文章已经太多了,小弟不多废话,贴一段代码提示记忆。
2、socketpair
基本类似 pipe,不过是基于 Unix domain socket,通信为双向通信。
3、共享内存
传统 SysV IPC 系列提供了 Shared Memory 实现,简称 sysv shm。它的优劣在 Stevens 前辈的 APUE 中都有了详细介绍,此处不多做赘述。Linux 2.4 及之后版本的内核提供了一种新的进程间共享内存方式:通过 mmap。指定 MAP_SHARED | MAP_ANONYMOUS,系统会创建一块可被子进程继承的共享匿名内存块。它的优点是:与其它 mmap 分配的内存具有相同属性:当附着进程执行 exec 或者退出的时候,内存会被系统自动收回,而不像 sysv shm 一样仍然被保留在系统中。而且,由于不需要 key 来进行标识,它的 API 也相对更简单清晰。直接看代码好了。
以上是一点学习心得,欢迎指正。
ps. 忽然想起前一段时间看到的 Win32 API 中 CreateFileMapping 如果指定第一个参数(文件句柄) hFile 为 INVALID_HANDLE_VALUE,则会在系统内存交换文件中创建一块映射区域。这大约是 Win32 在放弃了 SysV shm 之后的取代方案吧。
1、管道
Pipe 的特点:单向传递。在管道创建的时候,数据只能从读处读,从写处写,属于单向流动。相关文章已经太多了,小弟不多废话,贴一段代码提示记忆。
CODE:
[Copy to clipboard]
$ cat -n pipe.c
1 #include <unistd.h>
2 #include <assert.h>
3
4 int main ()
5 {
6 int fd[2];
7 #define READER 0
8 #define WRITER 1
9
10 int r = pipe( fd );
11 if ( r != 0 ) {
12 perror( "pipe()" );
13 exit( 1 );
14 }
15
16 if ( fork() ) {
17 /* Parent, writer */
18 int n = 0;
19 close( fd[READER] );
20 while ( 1 ) {
21 ++n;
22 write( fd[WRITER], &n, sizeof(n) );
23 sleep( 1 );
24 }
25 }
26 else {
27 /* Child, reader */
28 int n;
29 close( fd[WRITER] );
30 while ( 1 ) {
31 read( fd[READER], &n, sizeof(n) );
32 printf( "Got value: %d/n", n );
33 }
34 }
35 }
因为 pipe 只能进行单向传递的特性,popen(3) 的第二个参数只能为读写之一种,就是这个道理了。1 #include <unistd.h>
2 #include <assert.h>
3
4 int main ()
5 {
6 int fd[2];
7 #define READER 0
8 #define WRITER 1
9
10 int r = pipe( fd );
11 if ( r != 0 ) {
12 perror( "pipe()" );
13 exit( 1 );
14 }
15
16 if ( fork() ) {
17 /* Parent, writer */
18 int n = 0;
19 close( fd[READER] );
20 while ( 1 ) {
21 ++n;
22 write( fd[WRITER], &n, sizeof(n) );
23 sleep( 1 );
24 }
25 }
26 else {
27 /* Child, reader */
28 int n;
29 close( fd[WRITER] );
30 while ( 1 ) {
31 read( fd[READER], &n, sizeof(n) );
32 printf( "Got value: %d/n", n );
33 }
34 }
35 }
2、socketpair
基本类似 pipe,不过是基于 Unix domain socket,通信为双向通信。
CODE:
[Copy to clipboard]
$ cat -n socketpair.c
1 #include <sys/types.h>
2 #include <sys/socket.h>
3
4 #include <stdlib.h>
5 #include <stdio.h>
6
7 int main ()
8 {
9 int fd[2];
10
11 int r = socketpair( AF_UNIX, SOCK_STREAM, 0, fd );
12 if ( r < 0 ) {
13 perror( "socketpair()" );
14 exit( 1 );
15 }
16
17 if ( fork() ) {
18 /* Parent process: echo client */
19 int val = 0;
20 close( fd[1] );
21 while ( 1 ) {
22 sleep( 1 );
23 ++val;
24 printf( "Sending data: %d/n", val );
25 write( fd[0], &val, sizeof(val) );
26 read( fd[0], &val, sizeof(val) );
27 printf( "Data received: %d/n", val );
28 }
29 }
30 else {
31 /* Child process: echo server */
32 int val;
33 close( fd[0] );
34 while ( 1 ) {
35 read( fd[1], &val, sizeof(val) );
36 ++val;
37 write( fd[1], &val, sizeof(val) );
38 }
39 }
40 }
Linux 系统中,socketpair 的第一个参数只能是 AF_LOCAL / AF_UNIX。1 #include <sys/types.h>
2 #include <sys/socket.h>
3
4 #include <stdlib.h>
5 #include <stdio.h>
6
7 int main ()
8 {
9 int fd[2];
10
11 int r = socketpair( AF_UNIX, SOCK_STREAM, 0, fd );
12 if ( r < 0 ) {
13 perror( "socketpair()" );
14 exit( 1 );
15 }
16
17 if ( fork() ) {
18 /* Parent process: echo client */
19 int val = 0;
20 close( fd[1] );
21 while ( 1 ) {
22 sleep( 1 );
23 ++val;
24 printf( "Sending data: %d/n", val );
25 write( fd[0], &val, sizeof(val) );
26 read( fd[0], &val, sizeof(val) );
27 printf( "Data received: %d/n", val );
28 }
29 }
30 else {
31 /* Child process: echo server */
32 int val;
33 close( fd[0] );
34 while ( 1 ) {
35 read( fd[1], &val, sizeof(val) );
36 ++val;
37 write( fd[1], &val, sizeof(val) );
38 }
39 }
40 }
3、共享内存
传统 SysV IPC 系列提供了 Shared Memory 实现,简称 sysv shm。它的优劣在 Stevens 前辈的 APUE 中都有了详细介绍,此处不多做赘述。Linux 2.4 及之后版本的内核提供了一种新的进程间共享内存方式:通过 mmap。指定 MAP_SHARED | MAP_ANONYMOUS,系统会创建一块可被子进程继承的共享匿名内存块。它的优点是:与其它 mmap 分配的内存具有相同属性:当附着进程执行 exec 或者退出的时候,内存会被系统自动收回,而不像 sysv shm 一样仍然被保留在系统中。而且,由于不需要 key 来进行标识,它的 API 也相对更简单清晰。直接看代码好了。
CODE:
[Copy to clipboard]
$ cat -n mmap.c
1 #include <stdlib.h>
2 #include <stdio.h>
3
4 #include <sys/mman.h>
5
6 int main ()
7 {
8 int *p = mmap( NULL, sizeof(int),
9 PROT_READ|PROT_WRITE,
10 MAP_SHARED|MAP_ANONYMOUS, // 关键在这里。
11 0, 0 );
12 if ( p == MAP_FAILED ) {
13 perror( "mmap()" );
14 exit( 1 );
15 }
16
17 if ( fork() ) {
18 while ( 1 ) {
19 sleep( 1 );
20 printf( "Current val: %d/n", *p );
21 fflush(NULL);
22 }
23 }
24 else {
25 while ( 1 ) {
26 (*p)++;
27 sleep( 1 );
28 }
29 }
30 }
相比较之前两种方式,共享内存有许多不同。首先,它不是通过文件描述符进行标识,而是直接将虚拟页面映射到进程内存空间中;传递数据也不需要在用户空间 <-> 核心的三块 buf 之间来回传递;其次,当执行 exec 之后,进程空间被全部重新生成,mmap 会自动脱离被映射的地址而不会继续继承;第三,与 sysvshm 一样,使用过程需要其它的同步手段,而 pipe / socket 自身提供了同步机制。1 #include <stdlib.h>
2 #include <stdio.h>
3
4 #include <sys/mman.h>
5
6 int main ()
7 {
8 int *p = mmap( NULL, sizeof(int),
9 PROT_READ|PROT_WRITE,
10 MAP_SHARED|MAP_ANONYMOUS, // 关键在这里。
11 0, 0 );
12 if ( p == MAP_FAILED ) {
13 perror( "mmap()" );
14 exit( 1 );
15 }
16
17 if ( fork() ) {
18 while ( 1 ) {
19 sleep( 1 );
20 printf( "Current val: %d/n", *p );
21 fflush(NULL);
22 }
23 }
24 else {
25 while ( 1 ) {
26 (*p)++;
27 sleep( 1 );
28 }
29 }
30 }
以上是一点学习心得,欢迎指正。
ps. 忽然想起前一段时间看到的 Win32 API 中 CreateFileMapping 如果指定第一个参数(文件句柄) hFile 为 INVALID_HANDLE_VALUE,则会在系统内存交换文件中创建一块映射区域。这大约是 Win32 在放弃了 SysV shm 之后的取代方案吧。
- 父子进程间 IPC 总结
- [Linux] 由管道父进程向子进程发送数据 (父子间IPC)
- linux进程间通信(IPC)机制总结
- 父子进程间通信
- Linux 进程间通讯(IPC)详细总结 1管道。
- Linux 进程间通讯(IPC)详细总结 1管道
- Linux下C编程:进程间通信(IPC)总结
- Android进程间通信方式总结(IPC)
- Android中进程间通信(IPC)方式总结
- Android中进程间通信(IPC)方式总结
- Android中进程间通信(IPC)方式总结
- 进程间通信总结 && IPC主题三之 共享内存
- 父子进程间信号通信
- 父子进程间分发FD
- 父子进程间文件共享
- 进程间通信IPC
- 进程间通信IPC
- 进程间通信IPC
- 利用ISAPI实现向数据库中添加记录
- C/C++头文件一览
- 谁有类Outlook Express读取邮件的方法
- MultiBoolean for C++/Python
- 好多关于C语言,VC++学习的资料
- 父子进程间 IPC 总结
- 桌面精灵
- 编译器的相关知识
- 亲密接触VC6.0编译器
- CMinus编译器0.3版(含源代码)
- 通过#pragma pack(n)改变C编译器的字节对齐方式
- 编译原理课程设计_C--编译器_语法分析&代码生成
- 编译原理 —— 编译器各阶段工作
- 从lex&yacc说到编译器(1.正则表达式)