• linux IPC总结——管道


    管道

    管道是unix ipc的最古老形式,是一种在内存中的特殊文件,只能在具有公共祖先的进程之间使用(即父子进程,兄弟进程)。

    管道由pipe函数创建

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

    fd[1]写,fd[0]读。

    单个进程的管道几乎没有任何用处,通常,调用pipe的进程接着调用fork,这样就创建了父子进程间的管道。

    #include <unistd.h>
    #include<stdio.h>
    #include<sys/types.h>
    #include<sys/wait.h>
    
    int main()
    {
        int fd[2];
        char buf[80];
        pid_t pid;
        pipe(fd);
        pid = fork();
        if(pid>0)
        {//父进程
            printf("Father thread
    ");
            char s[]="Hello
    ";
            write(fd[1],s,sizeof(s));
            close(fd[0]);
            close(fd[1]);
        }
        else if(pid==0)
        {
            printf("Child Thread
    ");
            read(fd[0],buf,sizeof(buf));
            printf("%s
    ",buf);
            close(fd[0]);
            close(fd[1]);
        }
        waitpid(pid,NULL,0);//等待子进程结束
        return 0;
    }

     输出结果:

    Father thread
    Child Thread
    Hello

    当管道的一端关闭时:

      当读一个写端关闭的管道时,则认为已经读到了数据的末尾,读函数返回的读出字节数为0;

      当写一个读端关闭的管道时,向管道中写入数据的进程将收到内核传来的SIFPIPE信号,应用程序可以处理该信号,也可以忽略(默认动作则            是应用程序终止)。

    从管道中读取数据:

    当管道的写端存在时,如果请求的字节数目大于PIPE_BUF,则返回管道中现有的数据字节数,如果请求的字节数目不大于PIPE_BUF,则返回管道中现有数据字节数(此时,管道中数据量小于请求的数据量);或者返回请求的字节数(此时,管道中数据量不小于请求的数据量)。注:PIPE_BUF在include/linux/limits.h中定义。

    向管道中写入数据:

    向管道中写入数据时,linux将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读进程不读走管道缓冲区中的数据,那么写操作将一直阻塞。 

    管道因为没有名字所以只能用于具有亲缘关系的进程,而有名管道(FIFO)则克服了这个限制。

    FIFO

    创建函数如下

     #include <sys/types.h>
     #include <sys/stat.h>
    
     int mkfifo(const char *pathname, mode_t mode);

     第一个参数是一个普通的路径名,即为FIFO的名字。第二个参数设置权限,跟创建普通文件一样。

    FIFO的读写也像普通文件一样,不过需要读写端都打开,具体规则如下:

    当打开(open)时:

    若没有设置O_NONBLOCK,只读open要阻塞到其它进程为写而打开FIFO。类似地,只写open要阻塞到其它进程为读而打开FIFO。

    如果设置了O_NONBLOCK,则只读open立即返回,若没有其它进程为写而打开FIFO,则返回-1。

    用FIFO模拟生产者消费者问题:

    fifo2.cpp:

    #include<iostream>
    #include<unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include<limits.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    
    #define FIFO "/tmp/myfifo"
    #define BUF_SIZE PIPE_BUF
    #define SEND_MAX (1024*1024*10)
    using namespace std;
    
    int main()
    {
        int pid,fifo_fd;
        int send_num;
        char *buf[BUF_SIZE+1];
        if(-1 == access(FIFO,F_OK))
        {
            int res = mkfifo(FIFO,0777);
            if(res != 0)
            {
                fprintf(stderr,"can't create fifo in %s",FIFO);
                exit(EXIT_FAILURE);
            }
        }
    
        fifo_fd = open(FIFO,O_WRONLY);
        printf("process %d open fifo %d
    ",getpid(),fifo_fd);
        if(fifo_fd == -1)
            exit(EXIT_FAILURE);
        int res;
        while(send_num<SEND_MAX)
        {
            res = write(fifo_fd,buf,BUF_SIZE);
            if(res == -1)
            {
                cout<<"write fifo error"<<endl;
                exit(EXIT_FAILURE);
            }
            send_num += res;
        }
        return 0;
    }

     fifo3.cpp

    #include<iostream>
    #include<unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include<limits.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    
    #define FIFO "/tmp/myfifo"
    #define BUF_SIZE PIPE_BUF
    #define SEND_MAX (1024*1024*10)
    using namespace std;
    
    int main()
    {
        int fifo_fd;
        int res;
        char buffer[BUF_SIZE+1];
        int read_num = 0;
    
        fifo_fd = open(FIFO,O_RDONLY);
        printf("process %d open FIFO %d
    ",getpid(),fifo_fd);
        if(fifo_fd == -1)
            exit(EXIT_FAILURE);
        do{
            res = read(fifo_fd,buffer,BUF_SIZE);
            read_num += res;
        }while(res>0);
        close(fifo_fd);
        return 0;
    }

    结果如下:

    可见读进程运行0.013s就读取了10m的数据,FIFO的效率还是很高的。

  • 相关阅读:
    webpack引vue
    webpack加载css -loader
    webpack的使用
    leaflet(二)在地图上添加标记
    初学leaflet(一)引入地图资源
    Dom所有的属性,方法,和事件
    JavaScript所有函数和内置方法
    css padding 属性
    JavaScript正则表达式
    ES6 Promise
  • 原文地址:https://www.cnblogs.com/tonychen-tobeTopCoder/p/5296146.html
Copyright © 2020-2023  润新知