进程间通信

在用户应用程序在经常用到C库的进程间通信函数,实际上,这些进程间通信函数在内核中是通过系统调用好文件系统的机制实现的。

1 管道

管道是只用于连接读进程和写进程,以实现它们之间通信的共享文件。因而它又称共享文件。向管道(共享文件)提供输入的发送进程(即写进程),以字符流形式将大量的数据送入管道。而接受管道输出的接收进程(即读进程),可从管道中接收数据。由于发送进程和接收进程是利用管道进程通信的,所以将这些共享文件统称为管道。

为了协调双方的通信,管道通信机制必须提供以下三方面的协调能力。

  • 互斥。当一个进程正在对管道进行读写操作时,另一个进程必须等待。
  • 同步。当写(输入)进程把一定数量的数据写入管道后,便去睡眠等待,直到读(输出)进程取走数据后,再把它唤醒。当读进程读到一个空管道时,也应睡眠,直到写进程将数据写入管道后,才将它唤醒。
  • 确定通信双方的存在。只有确定通信的双方已经存在时,才能与对方进行通信。

管道是一个固定大小的缓冲区,缓冲的大小为1页,即4KB。管道借助了文件系统的file结构和VFS的索引节点inode。通过将两个file结构指向同一个临时的VFS索引节点,而这个索引节点又指向一个物理页而实现管道。它们定义的文件操作地址是不同的,其中一个是向管道中写入数据的例程地址,而另一个是从管道中读出数据的例程地址。这样,用户程序的系统调用仍然是通常的文件系统,而内核却利用这种抽象机制实现了管道这一特殊操作。

Linux支持命名管道。命名管道是一类特殊的FIFO文件,它像普通文件一样有名字,也想普通文件一样访问。它总是按照“先进先出”的原则工作,又称为FIFO管道。FIFO管道不是临时对象,它们是文件系统中的实体并且可以通过mkfifo命令来创建。

2 消息队列

消息队列就是一个消息的链表。具有权限的一个或者多个进程可对消息队列进行读写。

像管道线似的发送和接收函数的处理逻辑如下:

如果接收者没发现等待消息,它就把自己注册进等待接收者的链表里。发送者在向消息数组加新消息之前会检查链表。如果有一个等待的接收者,它就忽略消息数组,并且直接处理在接收者上的消息。

接收者在没有抢夺队列自旋锁的情况下接收消息并返回。

3 共享内存

进程A、B共享内存是指同一块物理内存被映射到进程A,B各自的进程地址空间。进程A可以及时看到进程B对共享内存中数据的更新,反之亦然。

共享内存方式有mmap()系统调用、Posix共享内存,以及系统V共享内存。其中mmap()系统调用是通过把普通文件在不同进程中打开并映射到内存后,在不同进程间可访问这个映射,最终达到共享内存的目的。

每个新创建的共享内存区域由一个shmid_ds数据结构来表示。它们被保存在shm_segs数组中。shmid_ds数据结构描述共享内存的大小,进程如何使用,以及共享内存映射到其各自地址空间的方式。由共享内存创建者控制对此内存的存取权限,以及其键是公有还是私有。如果它有足够的权限,则它还可以将此共享内存加载到物理内存中。

每个使用此共享内存的进程必须通过系统调用将其连接到虚拟内存上。这时进程创建新的vm_area_struct结构来描述此共享内存。

新的vm_area_struct结构被放到由shmid_ds指向的vm_area_struct链表中。通过vm_next_shared和vm_prev_shared指针将它们链接起来。虚拟内存在链接时并没有创建,进程访问它时才创建

当进程首次访问共享虚拟内存中的页面时,将产生页面错。当取回此页面后,Linux找到了描述此页面的vm_area_struct数据结构。它包含指向使用此种类型虚拟内存的处理函数的地址指针。共享内存页面错误处理代码将在此shmid_ds对应的页表入口链表中寻找是否存在此共享虚拟内存页面。如果不存在,则它将分配物理页面,并为其创建页入口。同时还将它放入当前进程的页表中,此入口被保存在shmid_ds结构中。这意味着下个试图访问此内存的进程还会产生页面错误,共享内存错误处理函数为此进程使用其新创建的物理页面这样,第一个访问虚拟内存页面的进程创建这块内存,随后的进程把此页面加入到各自的虚拟地址空间中

当进程不再共享此虚拟内存时,进程和共享内存的连接将被断开。如果其他进程还在使用这个内存,则此操作只影响当前进程。其对应的vm_area_struct结构将从shmid_ds结构中删除并回收。当前进程对应此共享内存地址的页表入口也被更新并置为无效。

当最后一个进程断开与共享内存的链接时,当前位于物理内存中的共享内存页面将被释放,同时还释放此共享内存的shmid_ds结构。

4 信号

信号用来向一个或多个进程发送异步事件信号,是在软件层次上对中断机制的一种模拟。进程间通信机制中只有信号是异步的。

从可靠方法考虑,信号分为可靠信号和不可靠信号。从实时性是上考虑,信号可分为实时信号与非实时信号。

不可靠信号时非实时信号。不可靠信号在每次处理进程后,信号的响应就会设置为默认动作。

可靠信号是实时信号,可靠信号是指后来添加的新信号。

实时信号和非实时信号的区别是,实时信号排队确保多个被发送的信号将被接收。

5 信号量

信号量主要是提供对进程间共享资源的访问控制机制,确保每次只有一个进程只有进行访问。信号量集是信号量的集合,用于多种共享资源进程间的同步。信号量的值表示当前共享资源可用的数量,如果一个进程要申请共享资源,那么就从信号量中减去要申请的数目,如果当前没有足够的可用资源,进程可以睡眠等待,也可以立即返回。

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。