管道以及管道间的通信

1、管道(pipe)

管道是一种最基本的IPC机制,由pipe函数创建:

#include<unistd.h>
int pipe(int filedes[2]);
调用pipe函数时在内核开辟一块缓存区(称为管道)用于通信,它有一个读端一个写端,然后通过filedes参数传出给用户程序两个文件描述符,filedes[0]指向管道的读端,filedes[1]指向管道的写端(0 输出, 1写入 );

匿名管道的特点:

1> 管道只能进行单向通信;
2> 管道只能用于有血缘关系的通信(父子进程)
3> 管道面向字节流间的一套服务
4> 管道依赖于文件系统,生命周期随进程退出(随进程)
5> 管道不用提供任何保护措施,自主完成了相关的同步,保证了数据的一致性;

下面展示匿名管道的代码:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>

int main()
{
	int pipefd[2] = {0,0};
	if(pipe(pipefd)<0){
		perror("pipe");
		return 1;
	}
	pid_t id = fork();
	if(id < 0){
		perror("fork");
		return 2;
	}else if(id == 0){//child-> write
		close(pipefd[0]);	//关闭读端
		const char* msg = "Hello bit";
		int count = 5;
		while(count){
			write(pipefd[1], msg, strlen(msg));//write to | 写到管道中
			count--;
			sleep(1);
		}
		close(pipefd[1]);
		exit(0);
	}else{//father-> read
		close(pipefd[1]);	//关闭写端

		int count  = 5;
		char buf[128];
		while(1){
			ssize_t _s = read(pipefd[0], buf,sizeof(buf)-1);//read from child
			if(_s > 0){
				buf[_s] = '\0';
				printf("child-> father :%s\n", buf);
			}else if(_s == 0){
				printf("pipe write is close\n");
				break;
			}
			count--;
		}
		close(pipefd[0]);
	}
}

对于匿名管道注意4个特殊情况:

1. 如果所有指向管道写端的文件描述符都关闭了(管道写端的引用计数等于0),而仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像读到文件末尾一样。

2. 如果有指向管道写端的⽂文件描述符没关闭(管道写端的引用计数大于0),而持有管道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。

3. 如果所有指向管道读端的文件描述符都关闭了(管道读端的引用计数等于0),这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。

4. 如果有指向管道读端的文件描述符没关闭(管道读端的引用计数大于0),而持有管道读端的 进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再次write会阻塞,直到管道中有空位置了才写入数据并返回。 


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值