进程间通信方式---管道

进程间通信方式—管道

管道的特点:

  1. 管道只允许具有血缘关系的进程间通信,比如父子进程间通信(后来的命名管道可以实现非血缘关系的进程间通信);
  2. 管道只允许单向通信;
  3. 管道内部保证同步机制,从而保证访问数据的一致性;
  4. 面向字节流;
  5. 管道的生命周期随进程,进程关闭,对应的管道端口关闭,两个进程都关闭,则管道关闭。
1.1 匿名管道

管道调用是调用pipe()函数来创建:

#include <unistd.h>
int pipe (int fd[2]);    //返回:成功返回0,出错返回-1  

fd参数用来存放创建管道返回的两个文件描述符,fd[0]指向管道的读端,fd[1]指向管道的写端。   

管道实现进程间通信:

  1. 父进程创建管道,得到两个文件描述符指向管道的两端;
  2. 父进程fork出子进程,子进程也有两个文件描述符,指向同一管道;
  3. 父进程关闭fd[0],子进程关闭fd[1],即父进程关闭管道读端,子进程关闭管道写端(因为管道只支持单向通信)。管道是用环形队列实现的,数据从写端写入,从读端读出,从而实现了进程间通信。
    在这里插入图片描述
实例:父进程读,子进程写
#include<stdio.h>
#include<unistd.h>
 #include<string.h>
int main()
{
int _pipe[2];
int ret=pipe(_pipe);
    if(ret<0)
    {
         perror("pipe\n");
    }
  pid_t id=fork();
  if(id<0)
{
       perror("fork\n");
   }
   else if(id==0)  // child
    {
        close(_pipe[0]);
        int i=0;
        char *mesg=NULL;
       while(i<100)
       {
           mesg="I am child";
           write(_pipe[1],mesg,strlen(mesg)+1);
           sleep(1);
           ++i;
        }
     }
    else  //father
   {
       close(_pipe[1]);
         int j=0;
        char _mesg[100];
         while(j<100)
        {
          memset(_mesg,'\0',sizeof(_mesg ));
          read(_pipe[0],_mesg,sizeof(_mesg));
          printf("%s\n",_mesg);
          j++;
        }
    }
   return 0;
}

结果演示:
在这里插入图片描述
总结:

  • 如果一个管道的写端一直在写,而读端的引用计数是否大于0,决定管道是否会堵塞;引用计数大于0,只写不读再次调用write会导致管道堵塞;
  • 如果一个管道的读端一直在读,而写端的引用计数是否大于0决定管道是否会堵塞;引用计数大于0,只读不写再次调用read会导致管道堵塞;
  • 当他们的引用计数等于0时,只写不读会导致写端的进程收到一个SIGPIPE信号,导致进程终止;只读不写会导致read返回0,就像读到文件末尾一样。
1.2 命名管道FIFO

  它提供一个路径名与之挂链,以FIFO的文件形式存储与文件系统中。命名管道是一个设备文件,因此,即使进程与创建FIFO的进程不存在亲缘关系,只要可以访问该路径,就能够通过FIFO相互通信。值得注意的是, FIFO(first input first output)总是按照先进先出的原则工作,第一个被写入的数据将首先从管道中读出。
命名管道的创建:
  创建命名管道的系统函数有两个: mknod和mkfifo。两个函数均定义在头文件sys/stat.h,这两个函数调用成功都返回0,失败都返回-1。
函数原型如下:

#include <sys/types.h>
#include <sys/stat.h>
//path为创建的命名管道的全路径名;
//mode为创建的命名管道的模,指明其存取权限;
//dev为设备值,该值取决于文件创建的种类,它只在创建设备文件时才会用到。
int mknod(const char *path,mode_t mode,dev_t dev);
//
int mkfifo(const char *path,mode_t mode);
umask(0);
if (mknod("/tmp/fifo",S_IFIFO | 0666) == -1)
{
      perror("mkfifo error");
      exit(1);
}

if (mkfifo("/tmp/fifo",S_IFIFO|0666) == -1)
   {
       perror("mkfifo error!");
        exit(1);
}

  "S_IFIFO|0666"指明创建一个命名管道且存取权限为0666,即创建者、与创建者同组的用户、其他用户对该命名管道的访问权限都是可读可写( 这里要注意umask对生成的管道文件权限的影响) 。命名管道创建后就可以使用了,命名管道和管道的使用方法法基本是相同的。只是使用命名管道时,必须先调用open()将其打开。因为命名管道是一个存在于硬盘上的文件,而管道是存在于内存中的特殊文件。
  需要注意的是,调用open()打开命名管道的进程可能会被阻塞。但如果同时用读写方式( O_RDWR)打开,则一定不会导致阻塞;如果以只读方式( O_RDONLY)打开,则调用open()函数的进程将会被阻塞直到有写方打开管道;同样以写方式( O_WRONLY)打开也会阻塞直到有读方式打开管道。

命名管道和匿名管道的区别

  1. 匿名管道只能用于有血缘关系的进程间通信;而命名管道可以在不相关的进程之间和不同计算机之间使用。
  2. 命名管道可以实现单向或双向通信,而匿名管道只能单向通信。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值