Linux系统编程——09-linux-day06(进程间通信)

    技术2022-07-12  78

    在学习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<stdio.h> 2 #include<unistd.h> 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<stdio.h> 2 #include<unistd.h> 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<stdio.h> 2 #include<unistd.h> 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,转载请注明出处。

    Processed: 0.017, SQL: 9