码迷,mamicode.com
首页 > 系统相关 > 详细

Linux 系统开发5 进程间通信 pipe() fifo() mmap()

时间:2016-08-09 00:42:50      阅读:319      评论:0      收藏:0      [点我收藏+]

标签:linux 系统开发5 进程间通信 pipe() fifo() mmap()


本文谢绝转载,原文来自http://990487026.blog.51cto.com



Linux 系统开发5 进程间通信 pipe() fifo() mmap()
	pipe()管道通信介绍
	pipe()父子进程通信案例
	pipe()使用管道有一些限制
	pipe()管道缓存区大小
	pipe() 读端非阻塞管道
	
	
	fifo()管道文件
	fifo()写端/读端程序
	管道文件在磁盘上的大小是0
	
	mmap()将文件映射到内存
	mmap()写端/读端程序
	mmap()传输结构体数据,删除临时文件



pipe()管道通信

管道作用于有学员关系的进程之间,通过fork()来传递

管道在kernel空间,先pipe在fork,进程继承


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

#include <unistd.h>

int pipe(int filedes[2]);

管道作用于有血缘关系的进程之间,通过fork来传递

调用pipe函数时在内核中开辟一块缓冲区(称为管道)用于通信,它有一个读端一个

写端,然后通过filedes参数传出给用户程序两个文件描述符,filedes[0]指向管道的读

端,filedes[1]指向管道的写端(很好记,就像0是标准输入1是标准输出一样)。所以管道

在用户程序看起来就像一个打开的文件,通过read(filedes[0]);或者write(filedes[1]);

向这个文件读写数据其实是在读写内核缓冲区。pipe函数调用成功返回0,调用失败返

回-1。

开辟了管道之后如何实现两个进程间的通信呢?比如可以按下面的步骤通信。

看图

技术分享





1.父进程调用pipe开辟管道,得到两个文件描述符指向管道的两端。

2.父进程调用fork创建子进程,那么子进程也有两个文件描述符指向同一管道。

3.父进程关闭管道读端,子进程关闭管道写端。父进程可以往管道里写,子进程可以从

管道里读,管道是用环形队列实现的,数据从写端流入从读端流出,这样就实现了进程间通

信。

例 pipe管道

chunli@ubuntu:~/linux_c$ cat main.c 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int num,char **args,char **env)
{
	int fd[2] = {0};
	char buf[1024] = "Hello World!  ";
	pid_t pid = 0;
	if(pipe(fd) == -1)
	{
		perror("pipe");
		exit(1);
	}
	pid = fork();
	//父写子读
	if(pid >0)	//在父进程,关闭父读
	{
		close(fd[0]);
		sleep(1);	//等n秒 再给子进程发数据
		write(fd[1],buf,strlen(buf));
		wait(NULL);
	}
	else if(pid == 0)//在子进程,关闭子写
	{
		char buf[1024] = {0};
		int len = 0;
		close(fd[1]);	//关闭写端
		len = read(fd[0],buf,sizeof(buf));
		sprintf(buf,"%s\n",buf);
		write(STDOUT_FILENO,buf,strlen(buf));
	}


	return 0;
}
chunli@ubuntu:~/linux_c$ gcc -o app main.c  && ./app
Hello World!  
chunli@ubuntu:~/linux_c$



使用管道有一些限制:


两个进程通过一个管道只能实现单向通信,比如上面的例子,父进程写子进程读,如果

有时候也需要子进程写父进程读,就必须另开一个管道。请读者思考,如果只开一个管道,

但是父进程不关闭读端,子进程也不关闭写端,双方都有读端和写端,为什么不能实现双向

通信?

管道的读写端通过打开的文件描述符来传递,因此要通信的两个进程必须从它们的公共

祖先那里继承管道文件描述符。上面的例子是父进程把文件描述符传给子进程之后父子进程

之间通信,也可以父进程fork两次,把文件描述符传给两个子进程,然后两个子进程之间通

信,总之需要通过fork传递文件描述符使两个进程都能访问同一管道,它们才能通信。

使用管道需要注意以下4种特殊情况(假设都是阻塞I/O操作,没有设置O_NONBLOCK标

志):

1.如果所有指向管道写端的文件描述符都关闭了(管道写端的引用计数等于0),而仍

然有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就

像读到文件末尾一样。

2.如果有指向管道写端的文件描述符没关闭(管道写端的引用计数大于0),而持有管

道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数

据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。

3.如果所有指向管道读端的文件描述符都关闭了(管道读端的引用计数等于0),这时

有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。讲

信号时会讲到怎样使SIGPIPE信号不终止进程。

4.如果有指向管道读端的文件描述符没关闭(管道读端的引用计数大于0),而持有管

道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时

再次write会阻塞,直到管道中有空位置了才写入数据并返回。

管道的这四种特殊情况具有普遍意义。

非阻塞管道, fcntl函数设置O_NONBLOCK标志

fpathconf(int fd, int name)测试管道缓冲区大小,_PC_PIPE_BUF



测试管道缓存区大小

chunli@ubuntu:~/linux_c$ cat main.c 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int num,char **args,char **env)
{
	int fd[2] = {0};
	pipe(fd);
	printf("%ld \n",fpathconf(fd[0],_PC_PIPE_BUF));

	return 0;
}
chunli@ubuntu:~/linux_c$ gcc main.c  && ./a.out
4096 
chunli@ubuntu:~/linux_c$


pipe() 读端非阻塞管道






本文出自 “魂斗罗” 博客,谢绝转载!

Linux 系统开发5 进程间通信 pipe() fifo() mmap()

标签:linux 系统开发5 进程间通信 pipe() fifo() mmap()

原文地址:http://990487026.blog.51cto.com/10133282/1835817

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!