进程通信——匿名管道实现和验证

本文介绍Linux中匿名管道的实现及特点,并通过父子进程通信实例验证其工作原理,包括单向通信、阻塞行为等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天我们来分享一下,Linux中关于进程通行中最简单的匿名管道的实现和相关性质的验证。

进程通信的原理是:多个进程看到同一份公共资源(文件),能对该资源进行相应操作,不同进程间即可进行通信。一般有操作系统(内核)提供这一公共资源。今天我们利用匿名管道来实现进程通信。

首先介绍一下,匿名管道的特点:

1.匿名管道只能实现单向通信。

2.匿名管道只能实现有血缘关系的进程之间的通信。

3.管道是一个随进程的文件,即当进程退出时,管道文件不存在。

4.管道的数据通信是基于数或者字节流的通信。

5.管道内部实现同步互斥,满足安全性,保证数据的一致性。

 

接着,举例父子进程的通信来说明匿名管道的通信过程。

A.利用pipe函数建立匿名管道,得到管道的读写文件描述符。

B.fork创建子进程。由于管道的读写文件描述符属于数据,子进程会依照父进程复制一份,即父子同时拥有指向管道文件的读写文件描述符,用有一份公共的管道文件,就拥有了进程通行的条件。

C.由于匿名管道只能实现进程间的单项通信,所以需要手动关闭父子进程冗余的读写端(读写文件描述符)。

注:子写父读,关闭子进程的读端和父进程的写端。需求不同则反之。

D.父子进程进行相应的读写,实现进程通信。

图解如下:

 

我们需要验证以下四种情况:

A.读端不关闭,且不读取管道内容,写端不断向管道写内容,当管道被写满,写端只能阻塞式等待。

部分代码截图和运行结果如下:

 

 

B.写端不关闭,且不向管道写内容,读端不断读取管道内容,当管道中数据读完,读端只能阻塞式等待。

部分代码截图和运行结果如下:

 

 

 

C.读端先于写端关闭,写端收到异常信号退出。

部分代码截图和运行结果如下:

 

 

D.写端先于读端关闭,当读到0时,即读到文件结尾,退出。

部分代码截图和运行结果如下:

 

 

 

实现进程通信——匿名管道,代码如下:

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
 
 int main()
 {
      umask(0);
      int pfd[2];
      if(pipe(pfd) < 0){
         perror("pipe wrong!\n");
          exit(1);
      }
  
      pid_t id = fork();
  
      if(id<0){
          perror("wrong!\n");
          exit(1);
      }
 
 	if(id == 0){//child
          close(pfd[0]);
          int i = 0;
          char* tmp = "hello !";
  //      while(1){
 //          i++;
 //          if(i < 5){
 //              printf("child: %s, num: %d\n", tmp, i);
 //              write(pfd[1], tmp, strlen(tmp));
 //          }
 //          else//i>=5
 //          {
 //              exit(1);
 //          }
 
 //      sleep(1);
 //      }
 //      exit(1);
          while(1){
         printf("child: %s, num: %d \n", tmp, i);
         i++;
         if(i>10)return 0;
 	write(pfd[1], tmp, strlen(tmp));
          }
      }
      else{//parent
      int status;
      close(pfd[1]);
      char tmp[1024];
  
      int i=0;
      while(1){
          ssize_t s = read(pfd[0], tmp, sizeof(tmp)-1);
  //      if(i>5) close(pfd[0]);
  //      i++;
          if(s>0){
              tmp[s] = 0;
              printf("parent:%s\n", tmp);
          }
          else if(s == 0){//child quit,so parent will quit
              printf("child quit,so parent will quit!\n");
              sleep(5);
              break;
          }
  //      else{//wrong
  //          printf("read wrong!\n");
  //          int status;
  //          pid_t s = waitpid(id, &status, 0);
  //          if(s>0){
  //       printf("waitpid success! sig:%d, exitCode: %d\n",\
  //              WIFEXITED(status),WEXITSTATUS(status) );
  //              }
  //          exit(2);
  //      }
      }
          if(waitpid(id, &status, 0)>0){
          printf("waitpid success! sig:%d, exitCode: %d\n",\
          WIFEXITED(status),WEXITSTATUS(status) );
          }
      }
      return 0;
  }


分享如上,欢迎斧正!

注:代码虽乱但全。若有错误和遗漏,请参见代码截图或评论!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值