214_进程通信
# 2.1_4_进程通信
各位同学大家好,在这个小节中我们会学习进程通信相关的知识点,进程通信可以用共享存储、消息传递和管道通信这样三个大类的方式来进行实现。大家在学习的过程中要注意体会各种实现方式背后进程通信的一个流程大概是什么样子,那么我们会按照从上至下的顺序依次进行讲解。
# 什么是进程通信
首先我们来看一下什么是进程通信,其实从字面上的意思也可以比较容易理也可以理解。进程通信指的就是进程之间的信息交换,信息传递。
那么我们知道进程它是分配系统资源,包括内存地址空间这样的系统资源的基本单位,各个进程拥有各自不同的内存地址空间,他们的地址空间是相互独立的,比如说进程一它可以访问它自己的地址空间进程,二也可以访问自己的地址空间,但是进程一并不能直接访问进程二的地址空间,因为这个地址空间它是操作系统分配给进程二的一个系统资源,这个资源是属于进程二的,不能被进程一所共享。
那么为了保证系统的安全,一个进程是不允许直接访问其他进程的地址空间的。可以想一下,如果进程一可以随意的访问进程二的地址空间的话,那么就意味着进程一可以修改进程二在内存当中存放的数据,这样显而易见是会对系统造成很大的安全隐患的。
但是有的时候进程之间的信息交换又是必须实现的,比如说大家在使用手机的手机自带的图片浏览的那个软件的时候,如果说有哪个照片你想分享给小伙伴,你可以直接用分享按钮,然后用微信进行发送,所以从图片进程到微信进程这两个进程之间肯定是有通信,肯定是有信息交换的,因此这种信息交换是肯定是必须要实现的,但是为了保证这个信息交换的安全性,操作系统就会提供一些方法来供各个进程使用。操作系统提供的进程通信方式分为共享存储、消息传递和管道通信这样三种。
# 共享存储
首先我们来看一下共享存储两个进程,他们不能直接访问对方的地址空间,所以操作系统会为两个进程分配一个共享空间,然后两个进程之间的通信就可以通过这个共享空间来进行完成。需要注意的是这两个进程对共享空间的访问必须是互斥的,当进程一正在往进共享空间当中写数据的时候,进程二是不允许访问共享空间的,只有进程一把这个共享空间的访问给释放了,那么进程二才可以开始读操作。
而这个互斥一般来说是使用操作系统提供的同步互斥工具来实现的,比如说之后咱们会学到的 pv 操作,这只需要有个印象,就可以之后会有更深入的理解。
那么共享存储会分为两种,第一种是基于数据结构的共享,第二种是基于存储区的共享
前者比如说共享空间当中只能存放一种固定的数据结构,比如说只能往里边存长度为 10 的数组,那么两个进程之间的通信每一次就只能传一个长度为 10 的数组,所以这种通信方式可以看到会极大的限制这种通信的速度,所以速度会很慢,并且对于数据的格式是有限制的。因此基于数据结构的这种共享,它是一种低级的通信方式。
而另外一种基于存储区的共享操作系统,只负责为通信的进程提供一个共享空间。但是在共享的存储空间当中,两个进程相互交换的数据是什么形式,存放在什么位置,这些其实都是由两个进程来相互决定的,不是由操作系统来决定。所以相比于前面这种来说,基于存储区的共享,它相对来说要更自由一些,并且它的数据传输速度会更快。因此基于存储区的共享,它是一种高级的通信方式,那么这就是通过共享存储实现的进程通信。
# 管道通信
第二种是管道通信,所谓的管道其实就是一个特殊的共享文件,那么管道其实就是在内存当中开辟的一个固定大小的缓冲区,缓冲区的大小一般和内存页面是一样的,像 Linux 系统当中,一个管道对应的缓冲区的大小就是 4KB。那么在管道通信当中大家需要注意的是,一个管道只能实现半双工的通信,所谓的半双工就是指在某一个时间段只能实现单向的传输,半双工的概念大家会在计算机网络里再进一步的学习,其实就是指数据其实是可以这样传输,也可以这样传输,但是在同一时间段内只能往一个方向传输,这就是半双工通信的意思。
那么如果用管道通信的方式想要实现双向同时通信的话,就需要设置两个管道,一个管道负责由左到右,另外一个管道负责另外一个方向的数据的传输。
而我们需要注意的是,各个进程对管道的访问其实也是需要互斥的进行的,和刚才咱们提到的共享空间的访问一样,当进程一正在往里边写的时候,进程二是不允许访问管道的,只有进程一把管道的访问给释放了,那么进程二才可以开始读。
那么我们来看一下管道通信的数据传输是怎么实现的,首先进程一会往管道当中写数据,当管道中的数据写满了之后,进程二才可以开始往外读数据,而只有这个数据全部被读出之后,进程一才可以继续往里边写数据。
那么在管道通信当中就有这样的一些特点,数据这些数据是以字符流的形式写入管道的,并且当管道写满的时候,进程就不可以继续往里边写数据了,写进程的 write 系统调用会被阻塞,需要等待读进程,把这些数据读出之后,写进程才可以继续往外往往里边写。
而如果说读进程把数据全部取走之后,管道为空,那么读进程的 read 系统调用又会被阻塞,需要等待写进程往里边写数据。而且大家需要注意的是,如果没有写满的话是不允许读的,同样如果没有读空的话是不允许写的。
另外管道中的数据一旦被读出之后就会被抛弃,那么这个数据就再也找不回来了。所以这就意味着在一个管道的读进程,最多只能有一个。如果有多个读进程的话,就有可能会发生读错数据的情况,比如说这些数据本来是应该由进程二读出的,如果有多个读进程的话,那么这些数据有可能会被另外一个进程给取走。而这些数据一旦被取走之后,就再也找不回来就被抛弃了,所以读进程最多只有一个。那么这就是管道通信。
# 消息传递
接下来我们再来看第三种消息传递进程之间会以格式化消息的方式来传递,这个消息传递的过程是用发送和接收两个原语来实现的。那么一个格式化的消息会分为消息头和消息体两个部分,消息头当中会包含发送进程的 ID,接收进程的 ID,还有什么消息类型、消息长度等等,各种各样的一系列的格式化的信息。
像咱们计算机网络当中发送的报文,其实就是一种格式化的消息,那么消息传递方式又分为两种,一种是直接通信方式,另外一种是间接通信方式。
直接通行方式其实就是把消息直接挂到接收进程的消息缓冲队列上,每一个进程会有一个消息缓冲队列,然后如果有另外一个进程想给他发送消息的时候,进程会首先创建好格式化的消息体,然后这个消息会通过发送原语发送给他目标进程,这个消息就会被挂到目标进程的消息缓冲队列的队尾,然后进程又会通过接收原语来依次把这些队列当中的这些消息一个取走,然后进行处理,这就是直接通信方式。
那么间接通信方式其实也比较类似,只不过这些消息是需要先发送到一个中间实体,这个中间实体可以称之为信箱,所以间接通信方式也可以称之为信箱通信方式,比如说像计算机网络里之后会学到的电子邮件系统就是一种间接通信方式,一种信箱通信方式,系统会为各个通信的进程管理一个信箱,而这个信箱当中可能会有各种各样的消息,并且这些消息可能是不同的进程之间通信的一些消息,具体是由哪个进程接收,这些都是在消息头里会包含的一些数据,所以并不需要担心这些消息会被取错。那么如果一个进程想要给另外一个进程发送消息的话,这个消息会用发送原语先发送到中间实体信箱当中,之后读进程会用接收原语再从信箱当中取走属于自己的消息
所以这就是消息传递的两种方式。
# 小结
好的,那么我们再来回顾一下小节的内容,大家需要理解各种通信方式的背后的一个通信的流程,那么共享存储当中需要保证各个进程是要互斥的访问这个共享空间。
而管道通信当中需要注意的是一个管道只能实现半双工通信,在同一时间段内只能实现单向的数据传输,而管道通信还有两个比较容易作为选择题考察的限制,在管道写满的时候就不能再写,在管道被读空的时候就不能再读,那么如果没有管道没有被写满的话,是不允许从管道中读取数据的,相应的没有被读空的话,也不能往管道里写数据。
之后我们又介绍了消息传递的两种方式,一种是直接通信方式和间接通信方式,他们都是用机发送接收言语来实现的。二者的区别在于间接通信方式是需要先把消息发送到一个中间体,一个信箱当中
好的,那么这就是小节的全部内容。