进程间通信之--- 管道


进程间通信之— 管道


  1. 在Linux系统中,有时候需要多个进程之间相互协作,共同完成某项任务,进程之间或线程之间有时候需要传递信息,有 时候需要同步协调彼此工作,则就会出现进程间通信(interprocess communication 或者 IPC)

  2. Linux下进程间通信有4种方式:管道,消息队列,信号量和共享内存。

学习进程间通信必须了解临界资源的概念
  1. 临界资源:把多个进程(执行流)能够看到访问的共同资源叫临界资源,管道是一种临界资源。
  2. 临界区:把访问临界资源的代码叫临界区。
  3. 进程间通讯的本质是二进程共享资源(不同进程看到公共资源),一进程以读方式一进程以写方式打开同一份文件
    linux 下一切接文件,管道也是一种特殊的文件。
  4. 互斥:在任意一个时刻只能有一个“人”访问临界资源,采用原子性原则访问。
  5. 原子性操作:狭义的原子性操作指该操作的汇编代码只有一句(该操作不可分),广义的原子操作指一个操作正在执行 时决不会被切出。原子操作要么做了,要么没做,不存在正在做。
管道的五个特点
  1. 管道只支持文件间的单向传输
  2. 管道面向字节流(以字节单位方式传输)
  3. 依赖于文件—-管道生命周期随进程(管道也是文件–> 有文件描述符表–> PCB –> 进程)
  4. 同步(一进程向管道文件写端写,同时一进程在管道文件读端读,两方面同时)
  5. 管道分匿名管道和命名管道。
    匿名管道只能在有亲缘关系的进程间通信,命名管道可以在无亲缘关系的进程间通信。
使用管道的注意
  1. 使用管道需要注意以下四种特殊情况(假设都是阻塞I/O操作,没有设置O_NONBLOCK标志)
  2. 如果所有指向管道写端的文件描述符都关闭了,(管道写端的引用计数为0),而仍然有进程从管道的读端读取数据,那么管道中剩余的数据都被读取之后,再次read将会返回0,就像读到文件结尾一样。也就是说,写端不会写,读端读完之后就会再等着写端去写,但是写端关闭了啊,不会写了,所以就出现上面说的情况。这就体现出了管道的同步机制。
  3. 如果有指向管道写端的文件描述符没有关闭,(管道写端的引用计数大于0)而持有管道写端的进程也没有向管道中写数据,这时有进程管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。通俗讲就是,读端读数据,一直读,但是写端不写了,而且写端并没有关闭,所以这时读端就会一直等着写端去写。这就造成了阻塞式等待。
  4. 如果所有指向管道读端的文件描述符都关闭了(管道读端的引用计数为0),这时有进程向管道的写端写数据,那么该进程会收到SIGPIPE,通常会导致进程异常终止。所以进程就会异常退出了。
  5. 如果有指向管道读端的文件描述符没关闭(管道读端的引用计数大于0)而持有管道读端的进程也没有从管道中读取数据,这时有进程向管道写端写数据,那么在管道写满时再写将会阻塞,直到管道中有了空位置才写入并返回,也就是管道的同步机制。
  6. 管道文件的大小是有限的写代码时一次不可一读写太多。
管道创建的图示
  1. A进程创建一个文件
  2. B进程拿到这个同样的文件
  3. A进程关闭读端 B进程关闭写端。(通过改变文件描述符表操作)
代码实现
//匿名管道:

#include<stdio.h>
 #include<unistd.h>
 #include<errno.h>
 #include<string.h>
 int main()
 {
     int _pipe[2];//定义参数
     int ret = pipe(_pipe);
     if(ret==-1)//创建管道失败
     {
         printf("creat pipe error!errno code is :%d\n",errno);//错误码
         return 1;//返回值,这样你就会知道到底是哪里出现了错误
     }
     pid_t id = fork();
     if(id<0)//创建子进程失败
     {
         printf("fork error!");
         return 2;
     }
     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);//xie
             sleep(1);
             i++;
         }
     }
     else
     {
         //father
         close(_pipe[1]);//关闭写端
         char _mesg_c[100];
         int j = 0;
         while(j<100)
         {
             memset(_mesg_c,'\0',sizeof(_mesg_c));
             read(_pipe[0],_mesg_c,sizeof(_mesg_c));
             printf("%s\n",_mesg_c);
             j++;
         }
     }
 }


//命名管道:


//写端
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
int main()
{
    umask(0);
    if(mkfifo("./mypipe",0666 | S_IFIFO)<0)
    {
        perror("mkfifo error");
        return 1;
    }
    int fd = open("./mypipe",O_RDONLY);
    if(fd<0)
    {
        printf("open file error!\n");
        return 2;
    }
    char buf[1024];
    while(1)
    {
        ssize_t ret = read(fd,buf,sizeof(buf)-1);
         if(ret>0)//error or end of file
             {
                 buf[ret] = 0;
                 printf("client say# %s\n",buf);
             }
         else if(ret==0)
         {
             printf("client quit !server begin quit!\n");
             break;
     }

   }
    close(fd);
    return 0;
}

//读端
#include<stdio.h>
 #include<sys/types.h>
 #include<sys/stat.h>
 #include<unistd.h>
 #include<fcntl.h>
 #include<string.h>
 int main()
 {
     int fd = open("./mypipe",O_WRONLY);
     if(fd<0)
     {
         printf("open file error!\n");
         return 2;
     }
     char buf[1024];
     while(1)
     {
         printf("please enter # ");
         fflush(stdout);
         ssize_t ret = read(0,buf,sizeof(buf)-1);
          if(ret>0)
              {
                  buf[ret-1] = 0;
                  write(fd,buf,strlen(buf));
              }

    }
     close(fd);
     return 0;
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值