进程间通信--管道

一:在开始之前,我们先搞明白这几个问题。

1.通信的目的?

让两个或多个进程实现数据传输、资源共享、通知事件、进程控制

2.进程间为什么不能直接通信?

在我们学完进程后,都知道,每个进程是独立的,都有自己的PCB,有自己独立的虚拟地址空间,就连父子进程也是数据写时拷贝,更别说其他进程了,因为在每个进程看来,自己享有所有的内存资源,所以两个资源是不可能直接通信的。所以,我们就必须让两个或多个进程能看到一份共同的资源,这样他们才能实现通信的目的。

3.

从上个问题当中我们就可以明白进程间通信的本质就是让不同的进程想办法看到一份公共资源。

二:进程通信的分类:

1.管道:

(1).匿名管道: int pipe(int pipefd[2]);pipe就是分别用读和写的方式打开文件,参数为打开文件的文件描述符,fd[0]表示读端,fd[1]表示写端。

先用pipe分别用读和写的方式打开一个文件,因为是以不同方式打开两次,所以有两个fd,再利用fork(),创建子进程,可以在子进程中向文件写东西(关闭读端),在父进程中读取文件的东西,这样就实现了不同进程访问同一个文件,从而达到进程通信的目的。

具体代码实现如下:
这里写图片描述

匿名管道实现的原理:

用pipe函数以读和写不同的两种方式分别打开文件,获得两个fd,这两个fd所对应的文件指针指向同一个文件,再通过fork创建子进程,因为父子进程代码共享,所以两个进程的PCB当中都保存了这个文件的文件指针,也就是说,这两个进程都可以访问这个文件,这样就实现了不同进程“看到”一份公共资源。这样就实现了不同进程通信的目的,过程如图所示:
这里写图片描述

管道的四种情况:

1.写端一直写,读端不读也不关,写端会一直写满,写端阻塞。
2.读端一直读,写端一直写,写端突然不写,但也不关,读端一直读,当管道为空时,读端就会阻塞。
3.写端不写,还关了,读端一直读,读到0,表示读到管道结尾。
4.写端一直写,读端不读,且关闭读端,写段会被操作系统发送信号异常终止掉(因为每人读,操作系统认为是浪费资源)。

特点:

1.管道自带互斥与同步机制
2.只有有血缘关系的两个进程,常见于父子进程通信
3.管道生命周期随进程
4.管道提供面向字节流的服务。
5. 只能进行单向通信;

解释:

1.数据不一致:读写双方因访问共同资源而导致的数据不一致性的问题
2.把两个毫不相干的进程看到的公共资源叫临界资源
3.把访问临界资源的代码叫临界区
4.访问资源的原子性:在进行某些资源的操作时,要么就不做,要做就做完,不会有中间状态,这种状态叫原子性。
5.互斥:在任何时间点,临界区访问临界资源的时候,有且仅有一个进程访问(上锁)
6.同步:让多个进程访问临界资源具有一定顺序性,这就叫同步。

(2)命名管道:

创建方式:
a.用命令创建:mkfifo filename
b.在程序中创建:int mkfifo(const char* filename, mode_t mode);//第一个参数为文件名,第二个为文件的权限,先用mkfifo创建共同访问的文件,管道,再在两个进程中打开这个文件,(一个以只读方式,另一个为只写),这样就创建出了一个命名管道
测试代码如下:
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

命名管道实现原理:

因为所有的进程通信方式,其本质就是让不同的进程看到一份公共资源,而命名管道就是通过创建管道文件,让不同进程都打开这个相同的管道文件,这样他们就可以看到一份公共资源,这样就实现了通信的目的。

命名管道与匿名管道的区别:

(1)匿名管道由pipe函数创建并打开,命名管道由mkfifo函数创建,由open打开
(2)匿名管道只能在具有血缘关系的进程间通信,而命名管道可以应用于不相关的进程间通信。
(3)命名管道是一种特殊类型的文件
(4)匿名管道是在硬盘上没有对应文件,在内存中实现;而命名管道是在硬盘上有对应的文件。

猜你喜欢

转载自blog.csdn.net/virgofarm/article/details/80375965