进程间通信-管道学习笔记

均为整理的资料,侵删.

IPC的通信方式-管道.管道一般分为匿名管道和有名管道.

管道是最基本的进程通信的方式.

匿名管道特点只能在父子进程之间进行使用.

有名管道客户克服管道没有名字的限制.因此,除了具有管道所具有的功能之外,还允许无亲缘关系进程之间的通信.

匿名管道(pipe)

特征:

  • 只提供单向通信,也就是说,两个进程都访问这个文件.如果进程1往文件内写东西,进程2只能读取文件的内容.
  • 只能用于具有血缘关系的进程间通信.通常是父子进程的通信
  • 管道是基于字节流进行通信的.
  • 依赖文件系统,生命周期随着进程的结束而结束.
  • 本身带有同步互斥的效果

要实现管道,我们首先介绍两个函数:
1.创建管道
调用 int pipe(int pipefd[2])

图片来源

  • 调用pipe函数的时候在内核中开辟了一块缓冲区用于通信,有一个读端一个写端,然后传出用户程序两个文件描述符,pipefd[0]指向管道的读端,pipefd[1]指向管道的写端(我们可以从0是标准输入,1是标准输出来记).所以管道在用户程序看起来就像一个打开的文件,我们可以通过调用read() 或者write() 向文件中读写数据.

  • 返回值 如果成功返回0,失败返回-1

  • 管道只能用于具有血缘关系的进程间通信,所以只有和fork之后产生的子进程进行交互.

实现通信的步骤如下:

  • 调用pipe函数,由父进程创建管道,得到两个文件描述符指向管道的两端.
  • 父进程调用fork创建子进程,对于子进程,也有两个文件描述符指向管道的两端.
  • 父进程关闭读段,只进行写操作;子进程关闭写端,只进行读操作.管道用唤醒队列实现,数据从写端到读端,形成了进程间通信.(原因是匿名管道只能单项通信)
//仅作参考例子
#include<unistd.h>
#include<cstring>
#include<unistd.h>
#include<bits/stdc++.h>
int main(){
    int fds[2];
    if(pipe(fds) == -1){
        perror("pipe");
        exit(1);
    }
    pid_t pid = fork();
    if(pid == 0){
        close(fds[0]);
        sleep(1);
        write(fds[1],"nihao",5);
        close(fds[1]);
        exit(0);
    }else{
        close(fds[1]);
        char buf[34]{};
        int re = read(fds[0],buf,34);
        printf("%s\n",buf);
        close(fds[0]);
        exit(0);
    }
    return 0;
}
有名管道(FIFO)

匿名管道虽然实现了进程间通信,但是有一定的局限性: 匿名管道必须是有血缘关系的进程进行通信; 第二它只能单工通信,一个进程写一个进程读.
有名管道

  • 提供了一个路径名与它关联,以FIFO文件的形式存储文件系统中,能够实现任何进程的通信.但是匿名管道对于文件系统不可见的,它仅仅限于父子进程的通信.
  • FIFO是一个设备文件,在文件系统中以文件名的形式存在.因此进程与创建FIFO的不存在血缘关系也可以通信,也是可以访问该路径的.
  • FIFO遵循先进先出的原则,第一个进来的数据也会被第一个读走.

系统函数创建

	- int mknod(const char * path,mode_t mod , dev_t dev);
	- int mkfifo(const char * path, mod_t mod);
  • 这两个函数都有创建一个FIFO文件,该文件在文件系统中真实存在.mknod 参数 path 为创建全路径,mod 为模式,存储权限,dev 是为设备的值,该值取决于文件创建的种类,它只是创建设备文件的时候才会使用.
  • FIFO 在文件系统中作为一个特殊的文件存在,但是FIFO中的内容存放在内存中.
  • 当使用FIFO的进程退出后,FIFO文件将继续保存在文件系统中以便后面使用.
  • FIFO有名字,不相关的进程可以通过打开命名管道进行通信.
#include <sys/types.h>
#include <sys/stat.h>
#include <bits/stdc++.h>
int main(){
    int ret  = mkfifo("test_fifo",0666);

    if(ret != 0){
        perror("mkfifo");
    }
    return 0;
}

在这里插入图片描述
后续的操作,我们可以把这个命名管道当作普通文件一样进行操作: open(),write(),read(),close().操作命名通道肯定要考虑默认情况的阻塞特性.

性质:

  • 如果以只读方式打开,阻塞某个进程为写而打开FIFO
  • 如果以只写方式打开, 阻塞某个进程为读而打开FIFO
  • 假如FIFO里没有数据,调用read 从FIFO进行读取的时候也会阻塞,这个特点和无名管道是一样的.
  • 通信过程中,如果写进程先退出,命名管道里没有数据,调用read函数从FIFO中读取不进行阻塞
  • 通信过程中,读进程退出后,写进程向命名管道内写数据,写进程也会收到SIGPIPE信号退出.
  • 调用write 函数向FIFO里写数据.当缓冲区满,write也会阻塞

举例

#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(){
    int re = open("test_fifo",O_RDWR);
    if(re < 0 ){
        perror("open error file");
    }
    char se[100] = "He"
    wirte(re,se,strlen(se));
    return 0;
}
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(){
    int re = open("test_fifo",O_RDWR);
    if(re < 0 ){
        perror("open error file");
    }
    char se[100] ;
    read(re,se,100);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值