美文网首页Linux
进程间通信(2)-无名管道

进程间通信(2)-无名管道

作者: 3e1094b2ef7b | 来源:发表于2017-05-08 18:17 被阅读12次
    无名管道通信框架

    要保证是对同一个管道进行操作。

    1、管道

    管道文件是一个特殊的文件,就是一个缓冲,是由队列来实现的,出队端读,入队端写。

    在文件IO中创建一个文件或打开一个文件是由open函数来实现的,但它不能创建管道文件,只能用pipe函数来创建管道。

    函数形式:
    int pipe(int fd[2])
    功能:创建管道,为系统调用:unistd.h(系统调用函数所在的.h文件)
    参数:就是得到的文件描述符。可见有两个文件描述符:fd[0]和fd[1],管道有一个读端fd[0]用来读和一个写端fd[1]用来写,这个规定不能变。
    返回值:成功是0,出错是-1;

    例1:pipe函数的使用

    #include "unistd.h"
    #include "stdio.h"
    #include "stdlib.h"
    
    int main()
    {
        int fd[2];
        int ret;
        ret = pipe(fd);
        if(ret < 0)
        {
            printf("create pipe fail\n");
            return -1;
        }
        printf("create pipe success fd[0]=%d, fd[1]=%d\n",fd[0],fd[1]);
        return 0;
    }
    

    解释:open函数如果创建成功,返回的文件描述符从3开始。
    因为一个进程打开时,内核会自动打开3个文件描述符:0、1、2。

    例2:pipe函数的使用

    #include "unistd.h"
    #include "stdio.h"
    #include "stdlib.h"
    
    int main()
    {
        int fd[2];
        int ret;
        char writebuf[] = "hello linux";
        char readbuf[128] = {0};
        ret = pipe(fd);
        if(ret < 0)
        {
            printf("create pipe fail\n");
            return -1;
        }
        printf("create pipe success fd[0]=%d, fd[1]=%d\n",fd[0],fd[1]);
    
        write(fd[1], writebuf, sizeof(writebuf));
        // start read from pipe
        read(fd[0], readbuf, 128);
        printf("readbuf = %s\n", readbuf);
    
        close(fd[0]);
        close(fd[1]);
        return 0;
    }
    
    确实读到了

    2、管道特点

    • 管道是创建在内存中的;进程结束,空间释放,管道就不存在了。
    • 管道中的东西,读完了就删除了(和队列是一样的)
    • 如果管道中没有东西可读,则会读阻塞。

    例3:验证读阻塞

    #include "unistd.h"
    #include "stdio.h"
    #include "stdlib.h"
    #include "string.h"
    
    int main()
    {
        int fd[2];
        int ret;
        char writebuf[] = "hello linux";
        char readbuf[128] = {0};
        ret = pipe(fd);
        if(ret < 0)
        {
            printf("create pipe fail\n");
            return -1;
        }
        printf("create pipe success fd[0]=%d, fd[1]=%d\n",fd[0],fd[1]);
    
        write(fd[1], writebuf, sizeof(writebuf));
        // start read from pipe
        read(fd[0], readbuf, 128);
        printf("readbuf = %s\n", readbuf);
    
        // second read from pipe
        memset(readbuf, 0, 128);
    
        read(fd[0], readbuf, 128);
        printf("second read complete\n");
    
        close(fd[0]);
        close(fd[1]);
        return 0;
    }
    
    1.第一次读完就删除了,因此第2次没东西读了;2.没东西可读了,就阻塞了

    例4:验证会写阻塞

    #include "unistd.h"
    #include "stdio.h"
    #include "stdlib.h"
    #include "string.h"
    
    int main()
    {
        int fd[2];
        int ret;
        int i = 0;
        char writebuf[] = "hello linux";
        char readbuf[128] = {0};
        ret = pipe(fd);
        if(ret < 0)
        {
            printf("create pipe fail\n");
            return -1;
        }
        printf("create pipe success fd[0]=%d, fd[1]=%d\n",fd[0],fd[1]);
    
        while(i < 5500)
        {
            write(fd[1], writebuf, sizeof(writebuf));
            i++;
        }
    
        printf("write pipe end\n");  // 如果存在写阻塞,这句话不会被打印出来
    
        close(fd[0]);
        close(fd[1]);
        return 0;
    }
    
    iwrite pipe end没有被打印出来,说明写阻塞了

    例5:验证写阻塞:可以计算出内核开辟的管道有多大。

    #include "unistd.h"
    #include "stdio.h"
    #include "stdlib.h"
    #include "string.h"
    
    int main()
    {
        int fd[2];
        int ret;
        int i = 0;
        char writebuf[] = "hello linux";
        char readbuf[128] = {0};
        ret = pipe(fd);
        if(ret < 0)
        {
            printf("create pipe fail\n");
            return -1;
        }
        printf("create pipe success fd[0]=%d, fd[1]=%d\n",fd[0],fd[1]);
    
        while(i < 5400)
        {
            write(fd[1], writebuf, sizeof(writebuf));
            i++;
        }
    
        printf("write pipe end\n");  // 如果存在写阻塞,这句话不会被打印出来
    
        close(fd[0]);
        close(fd[1]);
        return 0;
    }
    
    打印出来了,说明管道在5400到5500之间

    范围:5456-5457之间。即:5456是非阻塞,5457是阻塞。

    例6:通过管道实现进程间通信

    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    
    int main()
    {
        pid_t pid;
        int fd[2]; // 文件描述符数组
        int ret; // 返回值
        int process_inter = 0;
    
        // pipe必须放在子进程之前(pipe函数必须在fork函数之前)。这样才是同一个管道。
        ret = pipe(fd);
        if(fd<0)
        {
            printf("create pipe fail\n");
            return -1;
        }
        printf("create pipe success\n");
    
        pid = fork();
    
        if(pid == 0) // child process
        {
            int i = 0;
            read(fd[0], &process_inter, 1); // child process read
            while(process_inter == 0); // 如果读到是0,一直循环
            for(i = 0; i < 5; i++)  // 如果读到是1,就往下运行
            {
                printf("this is child process %d\n", i);
                usleep(100);
            }
        }
        if(pid>0)  // parent process 
        {
            int i = 0;
            for(i=0;i<5;i++)
            {
                printf("this is parent process i=%d\n", i);
                usleep(100);
            }
            process_inter = 1;
            sleep(5);  // 父进程运行完后,休眠5s
            write(fd[1], &process_inter, 1); // parent process write
        }
        while(1);
        return 0;
    }
    
    父进程先运行,之后休眠5s,子进程再运行

    3、无名管道的缺点

    只能实现父子关系或者有亲缘关系的进程间的通信。

    因为非父子关系的进程,在pipe函数创建无名管道时,都会各自创建一个管道,它们只能与各自创建的无名管道进行通信,这样它们俩就无法通过无名管道进行通信。

    相关文章

      网友评论

        本文标题:进程间通信(2)-无名管道

        本文链接:https://www.haomeiwen.com/subject/kecvtxtx.html