• Linux进程通信之匿名管道


    进程间的通信方式

      进程间的通信方式包括,管道、共享内存、信号、信号量、消息队列、套接字。

    进程间通信的目的

      进程间通信的主要目的是:数据传输、数据共享、事件通知、资源共享、进程控制等。

    进程间通信之管道

      管道(pipe):这种通讯方式有两种限制,一是半双工的通信,数据只能单向流动,二是只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
      流管道(s_pipe): 去除了第一种限制,可以双向传输。

      命名管道(name_pipe):克服了管道没有名字的限制,还允许无亲缘关系进程间的通信。

    Linux进程间通信机制

    管道的创建 

      pipe函数创建一个通信缓冲区,程序可以通过文件描述符fildes[0]和fildes[1]来访问这个缓冲区。返回值:成功返回0,错误返回-1。

    #include<unistd.h>
    int pipe(int fd[2]);

    管道的读写

      参数fd为管道描述符,同文件描述符,可以使用文件I/O函数(close, read, write)对其进行操作。fd[0]为管道读端,fd[1]为管道写端。如不需要,可以关闭相应端的描述符。写入fd[1]的数据可以按照先进先出的顺序从fildes[0]中读出。

    ssize_t read(fd[0], void *buf, size_t count);
    ssize_t write(fd[1], void *buf, size_t count);

    管道的实现

      调用fork()创建两个子进程,使用系统调用pipe()建立一个管道,两个子进程分别向管道各写一句话:
    Child process 1 is sending a message!
    Child process 2 is sending a message!
      而父进程则从管道中读出来自于两个子进程的信息,显示在屏幕上。然后分别结束两个子进程。

      注意事项:父进程和两个子进程间需要同步,使用waitpid()函数实现父进程等待子进程运行完毕后从管道中读取数据并打印。

      由于fork函数让子进程完整地拷贝了父进程的整个地址空间,所以子进程都有管道的读端和写端。所以在相关进程中最好关掉不用的那一端。

      要求“父进程先接收子进程P1发来的消息,然后再接收子进程P2发来的消息。”存在两个同步问题,两个子进程和父进程之间(先子写后父读)同步、子进程1和子进程2之间(先1写,再2写)。流程图如下所示:

    管道实现进程间通信流程图

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <errno.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    
    int main()
    {
        int status;
        pid_t p1;
        pid_t p2;
        int fd[2];
        char revbuf[100];
    
        int ret = pipe(fd);                // 创建管道
        if (ret == -1)                    // 管道返回值为-1则失败
        {  
            perror("Pipe error!
    ");
            exit(1);
        }
    
        if ((p1 = fork()) == 0)            //子进程p1
        {
            char *child1 = "Child process 1 is sending a message!";
    
            close(fd[0]);                //关闭管道读端
            write(fd[1], child1, strlen(child1));    //子进程1向管道写数据
        }
        else if (p1 > 0)                  //父进程
        {
            waitpid(p1, &status, 0);
    
            if ((p2 = fork()) == 0)        //子进程p2
            {
                char *child2 = "Child process 2 is sending a message!";
    
                close(fd[0]);            //关闭管道读端
                   write(fd[1], child2, strlen(child2));    //子进程2向管道写数据
            }
            else if (p2 > 0)            //父进程
            {
                close(fd[1]);          //关闭管道写端
    
                // waitpid(p1, &status, 0);
                read(fd[0], revbuf, 100);
                printf("The msg1: %s
    ", revbuf);
                waitpid(p2, &status, 0);
                read(fd[0], revbuf, 100);
                printf("The msg2: %s
    ", revbuf);
            }
            else                            //创建进程2失败
            {
                perror("Fork p2 error!
    ");
                exit(1);
            }
        }
        else                            //创建进程1失败
        {
            perror("Fork p1 error!
    ");
            exit(1);       
        }
        return  0;
    }
  • 相关阅读:
    797. 所有可能的路径
    1286. 字母组合迭代器
    216. 组合总和 III
    77. 组合
    784. 字母大小写全排列
    90. 子集 II
    78. 子集
    47. 全排列 II
    46. 全排列
    40. 组合总和 II
  • 原文地址:https://www.cnblogs.com/cjvae/p/9179329.html
Copyright © 2020-2023  润新知