在学习Linux系统编程总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。
09-linux-day06(进程间通信)
一、学习目标
1、熟练使用pipe进行父子进程间通信
2、熟练使用pipe进行兄弟进程间通信
3、熟练使用fifo进行无血缘关系的进程间通信
4、熟练掌握mmap函数的使用
5、掌握mmap创建匿名映射区的方法
6、使用mmap进行有血缘关系的进程间通信
7、使用mmap进行无血缘关系的进程间通信
二、进程通信
》IPC方法:进程间通信,通过内核提供的缓冲区进行数据交换的机制。
Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问,要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。
在进程间完成数据传递需要借助操作系统提供特殊的方法,如:文件、管道、信号、共享内存、消息队列、套接字、命名管道等。随着计算机的蓬勃发展,一些方法由于自身设计缺陷被淘汰或者弃用。现今常用的进程间通信方式有:
1)pipe 管道 (使用最简单)
2)fifo 信号 (开销最小)
3)mmap 共享映射区 (无血缘关系) 速度最快
4)本地socket 本地套接字 (最稳定)
5)信号(携带信息量最小)
6)共享内存
7)消息队列
1、管道的概念
管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。有如下特质:
1. 其本质是一个伪文件(实为内核缓冲区)
2. 由两个文件描述符引用,一个表示读端,一个表示写端。
3. 规定数据从管道的写端流入管道,从读端流出。
管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。
管道的局限性:
① 数据一旦被读走,便不在管道中存在,不可反复读取。
②由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。
③ 只能在有公共祖先的进程间使用管道。
常见的通信方式有,单工通信、半双工通信、全双工通信。
2、管道通信举例
man pipe
int pipe(int pipefd[2]);
pipefd读写文件描述符,0代表读,1代表写
返回值:失败返回-1,成功返回0
>touch pipe.c
>vi pipe.c
1 #include
2 #include
3
4 int main()
5 {
6 int fd[2];
7 pipe(fd);
8 pid_t pid = fork();
9
10 if(pid == 0){
11 //son
12 sleep(3);
13 write(fd[1],"hello",5);
14 }
15 else if(pid > 0){
16 //parent
17 char buf[12]={0};
18 int ret = read(fd[0],buf,sizeof(buf));//read会等待write写
19 if(ret > 0){
20 write(STDOUT_FILENO,buf,ret);
21 }
22 }
23 return 0;
24 }
>make
>./pipe
3、父子进程实现ps、grep命令
>touch pipe_ps.c
>vi pipe_ps.c
1 #include
2 #include
3
4 int main()
5 {
6 int fd[2];
7 pipe(fd);
8 pid_t pid = fork();
9
10 if(pid == 0){
11 //son
12 //son --> ps
13 //1.先重定向
14 dup2(fd[1],STDOUT_FILENO);//标准输出重定向到管道写端
15 //2.execlp
16 execlp("ps","ps","aux",NULL);
17 }
18 else if(pid > 0){
19 //parent
20 //1.先重定向,标准输入重定向到管道读端
21 dup2(fd[0],STDIN_FILENO);
22 //2.execlp
23 execlp("grep","grep","bash",NULL);//grep bash等待标准输入
24 }
25 return 0;
26 }
>make
>./pipe_ps
4、ps、grep命令实现问题解决
代码的问题:父进程认为还有写端存在,就有可能还有人给发数据,继续等待。
>vi pipe_ps.c
1 #include
2 #include
3
4 int main()
5 {
6 int fd[2];
7 pipe(fd);
8 pid_t pid = fork();
9
10 if(pid == 0){
11 //son
12 //son --> ps
13 //关闭读端
14 close(fd[0]);
15 //1.先重定向
16 dup2(fd[1],STDOUT_FILENO);//标准输出重定向到管道写端
17 //2.execlp
18 execlp("ps","ps","aux",NULL);
19 }
20 else if(pid > 0){
21 //parent
22 //关闭写端
23 close(fd[1]);
24 //1.先重定向,标准输入重定向到管道读端
25 dup2(fd[0],STDIN_FILENO);
26 //2.execlp
27 execlp("grep","grep","bash",NULL);//grep bash等待标准输入
28 }
29 return 0;
30 }
>make
>./pipe_ps
5、管道的读写行为
读管道:
写端全部关闭——read读到0,相当于读到文件末尾
写端没有全部关闭
有数据——read 读到数据
没有数据——read 阻塞 ,fcntl 函数可以更改非阻塞
写管道:
读端全部关闭——?产生一个信号SIGPIPE,程序异常终止
读端未全部关闭
管道已满——write阻塞。如果要显示现象,读端一直不读,写端狂写。
管道未满——write正常写入
6、管道大小和优劣
》计算管道大小
long fpathconf(int fd, int name);
ulimit -a
》优缺点
优点:简单
缺点:1)只能有血缘关系的进程通信;2)父子进程单方向通信,如果需要双向通信,需要创建多根管道。
7、fifo实现通信写端
8、fifo使用注意事项
9、mmap映射开始
在学习Linux系统编程总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。