【Linux】进程间通信——匿名管道|命名管道

目录

什么是进程间通信

管道

匿名管道


什么是进程间通信

进程间通信,顾名思义就是两个进程互相通信。

可是进程是独立的,该如何通信呢?

类比你和你的朋友在网上聊天,你们两个人也是独立的,是如何通信的呢?因为你能看到你朋友给你发的消息,你朋友也能看到这份消息。这个消息就是一个公共的资源。

所以进程间如果要进行通信,就需要两个进程看到同一份资源。

那么,通信的地点在哪里呢?

很明显,因为进程之间是独立的,所以通信的地点肯定不能在进程中,只能在操作系统中。

结论:进程间通信的地点是操作系统。

进程间通信的方式有很多,一般有三种:

1.管道:通过文件系统通信。

  • 匿名管道
  • 命名管道

2. system V:聚焦在本地通信

  • 共享内存
  • 消息队列
  • 信号量

3. POSIX:让通信可以跨主机。

  • 共享内存
  • 消息队列
  • 信号量
  • 互斥量
  • 条件变量
  • 读写锁

本文主要讲管道的通信方式。

管道

回顾文件系统

当父进程打开一个文件时,创建了一个子进程。子进程会继承父进程,包括继承父进程的文件描述符。子进程和父进程相同的fd指向同一个文件。

到这里,通信的条件就具有了,因为父子进程看到了同一份文件。

说明:在冯诺依曼体系结构中,磁盘是外设。而外设的读取速度是比较慢的。但是在进程间通信时,他们并不关心磁盘中有什么文件 - - - 说白了就是不会和磁盘进行交互。于是为了提升效率,就直接关闭了和磁盘中文件的交互。所以,这种不进行IO通信的文件,叫做内存级文件

那么,如果是内存级文件,需要如何进行通信呢?

1.父进程将内容写入到内存(struct file的内存缓冲区)中,

2.子进程从内存(struct file的内存缓冲区)中读取数据。

总共发生两次拷贝

结论:通过文件系统提供公共资源的进程间通信,叫做管道。

匿名管道

理论

定义:匿名管道,就是没有名字的管道。

使用范围:只能子在父子之间,或者父亲的所有孩子(兄弟)之间进行通信,也就是具有血缘关系才能通信。

原理:

第一步:父进程打开管道

从图中可以看到,fd[0]对应的是读端,对应父进程的3号文件描述符,

fd[1]对应的是写端,对应父进程的4号文件描述符。

fd[0]就是读端   fd[1]就是写端

第二步:父进程创建子进程,子进程会继承父进程的文件描述符

到这里,父子进程通信的管道(途径)就建立好了,但是管道就像水管一样,只能单向通信。所以,我们如果想要父进程写入,子进程读取,就需要关闭父进程的读端,子进程的写端。

第三步:父进程关闭读端(写端),子进程关闭写端(读端)

实践

查看手册,查找pipe函数。

解读:pipe函数的形参是一个pipefd[2]的数组,该数组有两个元素,分别是fd[0]和fd[1];其中,pipefd[0]代表读端,pipefd[1]代表写端。

返回值:如果创建成功,返回0,否则返回-1。

实现通过管道使父子进程通信

打印结果:

匿名管道读写特征(四种)

1.读快,写慢

写入慢,读取快,read调用阻塞,即进程暂停执行,一直等到有数据来到为止

2.读慢,写快

写入快,读取慢,write调用阻塞,直到有进程读走数据

3.写入端关闭,读取端未关闭

管道写端对应的文件描述符被关闭,则read返回0

当写入端关闭了,读取端就没有等待的必要了,读取端的read()直接返回0,表示写入端关闭了。

4.读取端关闭,写入端未关闭

管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE让write进程退出

匿名管道实现简易进程池

processPool.cc文件

task.hpp文件

运行结果:

命名管道

理论

使用范围:命名管道可以实现任何进程之间的通信。
命名管道实现的过程:

第一步:创建命名管道

使用指令:mkfifo 文件名   创建命名管道

创建命名管道之后,该如何让不同的进程看到同一份资源呢?

首先,我们需要将这个命名管道做唯一标识。

其次,让不同的文件都通过这个唯一标识,就能确定双方找到的文件是同一份文件了。

就好像钥匙和锁一样。现在有很多钥匙,A进程手里10把要是,B进程手里10把钥匙,现在A和B进程都找自己的钥匙,只要能打开同一把锁,就是相同的钥匙。

如何做到唯一标识?

之前在文件系统中说到,为什么同一个目录下的文件不能重名?就是因为目录下存的是文件的文件名,目录通过文件名找文件,所以,不能重名。

这里同理,利用同一路径 + 文件名的方式唯一标识文件

第二步:进程之间使用命名管道通信

通信过程和匿名管道一样。

第三步:删除命名管道(如果不在程序中删除,就要自己手动删除)

使用指令:unlink 文件名

实践

创建命名管道

参数:

第一个参数是pathname,表示要创建的管道文件所在的路径文件名

第二个参数是权限,一般设置0666或者0664

作用:

创建一个命名管道

返回值:

如果创建成功,则返回0,否则返回-1

使用:

进程之间使用命名管道通信

实现命名管道通信,需要两个进程,我们姑且将两个进程命名为客户端(client)和服务端(sliver),客户端发信息,服务端接受信息。

客户端写入

服务端读取

服务端程序

只读端,打开管道文件的方式是O_RDONLY。

接下来就是文件描述符fd中读取sizeof(buffer)个字节内容到buffer中。为了方便观察,将buffer中的内容打印到显示器上。

客户端程序

写入端打开文件的时候使用O_WRONLY

之后将内容输入到line中,将line中的内容写入到fd中,拱读取端去读

实现进程间通信完整程序

实现日志

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值