Linux 伍之型 进程间通信(管道、共享内存、消息队列、信号量)

           看进程之间怎么说悄悄话~

      因为进程有独立性,有个字

        先理解一下,进程通信 : 不同进程之间传播或交换信息 

        那为什么要进程通信呢? 协同运行(数据传输、数据共享、进程控制),项目模块化 (低耦合)。 

      那为什么进程通信需要os控制呢? 为了保证进程的独立性,让每个进程稳定运行,用户很难控制,难事都交给os做吧~

      通信原理 : 给多个进程提供一个都能访问到的缓冲区

      根据使用场景,我们能划分为以下几种通信 :

    1.管道(匿名管道、命名管道) 

      管道是从Unix继承下来的进程通信机制,其思想就是 : 在内核中创建一个缓冲区让通信双方传递信息。"管道"是半双工通信(单向传递信息)。

    

             匿名管道 : 创建的缓冲区没有标识 , 只能用于具有亲缘关系的进程通信

                 通信流程及代码: 

                

                                                                  

/*
*  匿名管道接口的基本使用
*/

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>

int main()
{
    //创建管道 必须在子进程创建之前
    //int pipe(int pipefd[2]);
    //pipefd : 用于获取管道中的操作描述符
    //pipefd[0] : 用于从管道中读取数据
    //pipefd[1] : 用于向管道中写入数据
    //返回值 : 成功 0 失败 -1
    int pipefd[2];
    int ret = pipe(pipefd);
    if(ret < 0)
    {
        perror("pipe error");
        return -1;
    }
    
    int pid = fork();
    if(pid < 0)
    {
        return -1;
    }
    else if(pid == 0)
    {
        //子进程关闭写端
        close(pipefd[1]);
        //子进程--读取管道中的数据
        char buff[1024] = {0};
        read(pipefd[0],buff,1023);
        printf("buff:[%s]\n",buff);
    }
    else
    {
        //父进程关闭读端
        close(pipefd[0]);
        //父进程--向管道中写入数据
        char *ptr = "do you like me ?";
        write(pipefd[1],buff,strlen(ptr));
    }
    
    return 0;
}    

                管道的读写特性 :

                   如果管道中没有数据,则read会阻塞,直到读取到数据

                     如果管道中数据满了,则write会阻塞,直到有数据被读取出去

                     如果管道中所有写端都被关闭,那么读端读完管道中的数据之后,会返回0

                     如果管道中所有读端都被关闭,那么写端写入数据的时候会触发异常,退出进程

                管道特点 :

                   1.半双工通信,数据只能一个方向流动

                   2.读写特性

                   3.内核会对管道进行同步与互斥操作(如果管道读写数据大小<=PIPE_BUF,读写操作将是原子性操作,是不可中断的)

                   4.提供字节流(不包含边界的连续流)服务(数据的传输比较灵活,但是有可能造成数据粘连(数据没有边界) )

                     5.生命周期随进程退出而退出 

                下面,用匿名管道实现ls | grep 命令:

//ls|grep的模拟实现
#include<stdio.h>
#include<unistd.h>
#include<errno.h>

int main()
{
    //创建匿名管道
    int pipefd[2];
    int ret = pipe(pipefd);
    if(ret<0)
    {
        perror("pipe error\n");
        return -1;
    }
    
    int pid1=fork();
    if(pid1==0)
    {
        //ls --- 写入到标准输出进行打印
        //标准输出重定向到管道写端
        close(pipefd[0]);           
        dup2(pipefd[1],1);
        execlp("ls","ls",NULL);
        exit(0);
    }
    int pid2=fork();
    if(pid2==0)
    {
        //grep make --- 从标准输入读取数据
        //标准输入重定向到管道读端
        close(pipefd[1]);  
        dup2(pipefd[0],0);
        execlp("grep","grep","make",NULL);
        exit(0);
    }
    
    //wait之前关闭管道,防止影响子进程之间的管道交流
    close(pipefd[0]);   
    close(pipefd[1]);
    wait(NULL);
    wait(NULL);
    return 0;
}

                命名管道 : 可见于文件系统创建的一个管道文件,所有进程都可以通过打开文件获取内核管道的文件描述符。

                  特点 : 能让同一机器任意进程都可以进行通信

                  打开特性 : 

                    管道文件如果被只读/只写方式打开,将阻塞,直到该文件被只写/只读方式打开;

                    被读写方式打开,不阻塞。

                  通信流程及代码 : 

                     写端mkfifo创建管道文件->读端打开管道->两端可以进行单向通信了

//命名管道 读端demo
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>
#include<errno.h>

int main()
{
    int fd=open("./test.fifo",O_RDONLY);
    while(1)
    {
        char buff[1024]={0};
        int ret=read(fd,buff,1023);
        if(ret>0)
        {
        printf("client say:%s\n",buff);
        }
        else if(ret == 0)
        {
        printf("write close!\n");
        return -1;
        }
        else 
        {
        perror("read error");
        return -1;
        }
    }    
    close(fd);
    return 0;
}
//命名管道基本使用 写端demo
//   int mkfifo(cosnt char* pathname,mode_t mode)
//   mode : 权限 返回值: 成功0  失败-1
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include<fcntl.h>
#include<sys/stat.h>

int main()
{
    int ret = mkfifo("./test.fifo",0664);
    if(ret<0)
    {
        perror("mkfifio error");
        return -1;
    }
    
    int fd = open("./test.fifo",O_WRONLY);
    if(fd<0)
    {
        perror("open error");
        return -1;
    }
    printf("open fifo success!\n");

    while(1)
    {
        char buff[1024] = {0};
        scanf("%s",buff);
        write(fd,buff,strlen(buff));
        printf("buff:[%s]\n",buff);
    }        
    close(fd);
    return 0;
}

               运行演示 : 

                

                  

               

            

  

 

             

      

     

            

 

    

猜你喜欢

转载自www.cnblogs.com/Duikerdd/p/11737374.html
今日推荐