进程间通信概述
- 数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几兆字节之间
- 共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到。
- 通知时间:一个进程需要向另一个或一组进程发送消息,通知他们发生了某些事件(如进程终止时要通知父进程)
- 资源共享:多个进程之间共享同样的资源,为了做到这一点,需要内核提供锁和同步机制
- 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入的异常,并能够及时指导它的状态改变。
进程间通信方式
- 管道(pipe),有名管道(FIFO)
- 信号(signal)
- 消息队列
- 共享内存
- 信号量
- 套接字(socket)
管道
- 管道针对本地计算机的两个进程之间的通信而设计的通信方式,管道建立后,实际获得两个文件描述符:一个用于读取另一个用于写入。
- 常见的IPC机制,通过pipe系统调用。
- 管道单工,数据只能向一个方向流动。双向通信时,需要建立两个管道。
- 数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道的缓冲区的尾部,每次都是从缓冲区的头部读出数据。
管道的分类
- 匿名管道
- 关系进程,父子或兄弟
- 由pipe系统调用,管道由父进程建立
- 管道位于内核空间,其实是一块缓存
- 有名管道(FIFO)
- 两个没有任何关系的进程之间通信可通过有名管道进行数据传输
- 通过系统调用mkfifo创建
管道创建
#include<unistd.h>
int(int[2]);
//返回:0成功,-1出错
- 两个文件描述符数组
- fd[0]:pipe的读端
- fd[1]:pipe的写端
管道通信是单向的阻塞性IO
借助管道使两个子进程相互通讯
- 一个子进程调用execvp函数,将执行结果写入管道
- 另外一个子进程也是调用execvp函数,从管道中读取命令结果进行过滤。
- 涉及改变标准输入输出,重定向。
$ cat /etc/passwd |grep root
1 #include <unistd.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4
5 char *cmd1[3]={"/bin/cat","/etc/passwd",NULL};
6 char *cmd2[3]={"/bin/grep","root",NULL};
7
8 int main(void)
9 {
10 int fd[2];
11 if(pipe(fd)<0)
12 {
13 perror("pipe error");
14 exit(1);
15 }
16 int i=1;
17 pid_t pid;
18 for(;i<=2;i++)
19 {
20 pid=fork();
21 if(pid<0)
22 {
23 perror("fork error");
24 exit(1);
25 }
26 else if(pid==0)
27 {
28 //child process
29 if(i==1)
30 {
31 //子进程1,负责写入数据
32 close(fd[0]);//关闭读端
33
34 //将标准输出重定向到管段的写端
35 if(dup2(fd[1],STDOUT_FILENO)
36 !=STDOUT_FILENO)
37 {
38 perror("dup2 error");
39 }
40 close(fd[1]);
41
42 //调用exec函数执行cat命令
43 if(execvp(cmd1[0],cmd1<0))
44 {
45 perror("excvp error");
46 exit(1);
47 }
48 break;
49 }
50 if(i==2)
51 {
52 //子进程2,负责从管道读取数据
53 close(fd[1]);//关闭写端
54
55 //将标准输入重定向到管道的读端
56 if(dup2(fd[0],STDIN_FILENO)
57 !=STDIN_FILENO)
58 {
59 perror("dup2 error");
60 }
61 close(fd[0]);
62
63 //调用exec函数执行grep命令
64 if(execvp(cmd2[0],cmd2)<0)
65 {
66 perror("execvp error");
67 exit(1);
68 }
69 break;
70
71 }
72 }else
73 {
74 //parent process
75 if(i==2)
76 {
77 //父进程要等到子进程全部创建完毕才去回收
78 close(fd[0]);
79 close(fd[1]);
80 wait(0);
81 wait(0);
82 }
83 }
84 }
85 }