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管道

[email protected]:~/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;
}
[email protected]:~/linux_c$ gcc -o app main.c  && ./app
Hello World!  
[email protected]:~/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

测试管道缓存区大小

[email protected]:~/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;
}
[email protected]:~/linux_c$ gcc main.c  && ./a.out
4096 
[email protected]:~/linux_c$

pipe() 读端非阻塞管道

时间: 2024-10-15 17:24:42

Linux 系统开发5 进程间通信 pipe() fifo() mmap()的相关文章

Linux系统开发6 信号

[本文谢绝转载,原文来自http://990487026.blog.51cto.com] <大纲> Linux系统开发6 信号 linux系统有64种信号 signal man文档 终端按键信号 ctrl +c SIGIN ctrl +z SIGTSTP ctrl +\ SIGQUIT 硬件产生信号 浮点数例外信号  访问非法内存 kill()函数 信号与权限 kill()函数的pid 与返回值 信号产生原因 raise() 信号 abort() 信号 alarm() 信号 收到信号的默认操作

Linux系统开发8 线程

[本文谢绝转载原文来自http://990487026.blog.51cto.com] <大纲> Linux系统开发8 线程 线程概念 浏览器 火狐多线程,谷歌多进程比较: 查看某一个进程有哪些线程 线程间共享资源 线程间非共享资源 线程优缺点 安装完整的manpage文档 pthread_create()创建线程 pthread_self() 获取线程自己的ID 线程创建程序演示: 指定libpthread.so库编译链接 演示:进程结束,线程也会立即结束 pthread_exit() 调用

Linux系统开发7 进程关系,守护进程

[本文谢绝转载原文来自http://990487026.blog.51cto.com] <大纲> Linux系统开发7  进程关系守护进程 终端 网络终端 Linux PCB结构体信息 进程组 修改子进程.父进程的组ID 会话组 设置一个会话脱离控制终端 生成一个新的会话 守护进程 守护进程模板 获取当前系统时间  终端 在UNIX系统中用户通过终端登录系统后得到一个Shell进程这个终端成为Shell进 程的控制终端Controlling Terminal在讲进程时讲过控制终端是保存在PCB

Linux系统开发 2 文件IO open() close() read() write() perror() lseek() fcntl() ioctl()

[本文谢绝转载,原文来自http://990487026.blog.51cto.com] 大纲 Linux系统开发 man 文档的使用 文件IO open() 创建文件,指定权限位 open() 接收参数 创建文件 open() 传两个参数 第三个参数从内存取垃圾值 write()函数 向文件写数据 write()函数的覆盖操作 open()函数文件的追加 open() 创建文件,如果文件已经存在,就报错 测试一个程序最多能创建1021个文件,3个STDIN STDOUT STDERR已经存在了

Linux系统开发 3 文件系统开发 文件/目录

[本文谢绝转载,原文来自http://990487026.blog.51cto.com] Linux系统开发 文件操作 ext2文件系统了解 stat()函数 access()函数 chmod()函数 utime()函数 truncate()函数 link()硬链接函数 symlink()软链接函数 readlink()函数 unlink函数 rename函数() 目录操作 chdir()/fchdir() getcwd/getwd()/get_current_dir_name() pathco

Linux系统开发学习路线

一:嵌入式c语言 C语言是嵌入式领域最重要也是最主要的编程语言,通过大量编程实例重点理解C语言的基础编程以及高级编程知识.包括:基本数据类型.数组.指针.结构体.链表.文件操作.队列.栈等. 二:Linux基础 Linux操作系统的概念.安装方法,详细了解Linux下的目录结构.基本命令.编辑器VI ,编译器GCC,调试器GDB和 Make 项目管理工具, Shell Makefile脚本编写等知识,嵌入式开发环境的搭建. 三:Linux系统编程 重点学习标准IO库,Linux多任务编程中的多进

Linux 系统应用编程——进程间通信(下)

在前面,我们学习了传统的进程间通信方式--无名管道(pipe).有名管道(fifo)和信号(signal). 下面我们来学习 System V  IPC 对象: 1.共享内存(share memory): 2.信号灯(semaohore): 3.消息队列(message queue):        IPC对象是活动在内核级别的一种进程间通信的工具.存在的IPC对象通过它的标识符来引用和访问,这个标识符是一个非负整数,它唯一的标识了一个IPC对象,这个IPC对象可以是消息队列或信号量或共享存储器

Linux系统编程之进程间通信

今天我们接着谈Linux系统编程中的进程间的通信,上一节我们讨论了进程的基本操作.这一节我们来讨论一下进程间的通信.        常见的进程间的通信方式有:无名管道.命名管道.信号.共享内存.消息队列.信号量.套接字. 接下来我们先来谈:                一.无名管道:                      1.管道是UNIX系统的IPC的最古老方式,并且多数unix系统都提供此种通信方式..                      2.管道是一种半双工的通信方式,数据只能

Linux系统开发9 线程同步

[本文谢绝转载原文来自http://990487026.blog.51cto.com] <大纲> Linux系统编程8 线程同步 多线程共享资源,不加锁,同步互斥演示 多线程共享资源,加锁,同步互斥演示 读写锁:3个写线程,5个读线程,不加锁,并行处理 读写锁:3个写线程,5个读线程,加读写锁,串行处理 条件变量:生产消费者模型 信号量 进程间锁 文件锁: 习题 死锁,哲学家就餐 多线程共享资源,不加锁,同步互斥演示 [email protected]:~/linux_c/thread$ ca