Linux内核如何在两个进程之间实现共享内存?

4
Linux内核如何在不同进程之间实现共享内存机制?
进一步来说,每个进程都有自己的地址空间。例如,对于进程A中的地址0x1000和进程B中的地址0x1000而言,它们所代表的位置是不同的。
那么,内核如何确保一个内存块可以在具有不同地址空间的不同进程之间共享呢?
谢谢。
2个回答

1

进程间通信机制

进程之间以及与内核进行通信以协调它们的活动。Linux支持多种进程间通信(IPC)机制。其中信号和管道是其中两种,但Linux还支持System V IPC机制,这些机制是以它们首次出现的Unix TM版本命名的。

信号

信号是Unix TM系统使用的最古老的进程间通信方法之一。它们用于向一个或多个进程发出异步事件信号。信号可以由键盘中断或错误条件(例如进程尝试访问其虚拟内存中不存在的位置)生成。Shell也使用信号向其子进程发送作业控制命令。内核可以生成一组定义好的信号,或者其他进程在系统中生成它们,前提是它们具有正确的权限。您可以使用kill命令(kill -l)列出系统的信号集。

管道

常见的Linux shell都允许重定向。例如:

$ ls | pr | lpr

将ls命令列出目录文件的输出管道传输到分页pr命令的标准输入,最后将pr命令的标准输出管道传输到打印机lpr命令的标准输入,以在默认打印机上打印结果。管道是单向字节流,将一个进程的标准输出连接到另一个进程的标准输入。两个进程都不知道这种重定向,并像平常一样运行。这是shell在进程之间设置这些临时管道。

enter image description here

在Linux中,管道使用两个文件数据结构实现,它们都指向同一个临时VFS inode,该inode本身指向内存中的物理页面。如图所示,每个文件数据结构都包含指向不同文件操作例程向量的指针;一个用于向管道写入,另一个用于从管道读取。 套接字
  • 消息队列:消息队列允许一个或多个进程写入消息,这些消息将被一个或多个读取进程读取。Linux维护着一个消息队列列表,即msgque向量;其中每个元素都指向一个完全描述消息队列的msqid_ds数据结构。当创建消息队列时,系统会从系统内存中分配一个新的msqid_ds数据结构,并将其插入到向量中。
  • System V IPC机制:Linux支持三种在Unix TM System V (1983)中首次出现的进程间通信机制。它们是消息队列、信号量和共享内存。这些System V IPC机制都共享常见的身份验证方法。进程只能通过传递唯一的引用标识符来通过系统调用将这些资源传递给内核来访问这些资源。对这些System V IPC对象的访问使用访问权限进行检查,就像对文件的访问一样进行检查。对象的访问权限由对象的创建者通过系统调用设置。每种机制使用对象的引用标识符作为资源表中的索引。这不是一个简单的索引,而需要进行一些操作才能生成索引。
  • 信号量:在其最简单的形式下,信号量是内存中的一个位置,它的值可以被多个进程测试和设置。就每个进程而言,测试和设置操作是不可中断或原子的;一旦开始就没有任何东西可以停止它。测试和设置操作的结果是信号量的当前值和设置值的相加,这个值可以是正数或负数。根据测试和设置操作的结果,一个进程可能需要休眠,直到另一个进程更改了semaphore的值。信号量可用于实现关键区域,即只有一个进程在执行临界代码的关键代码区域。
假设你有很多协作进程从单个数据文件中读取记录并写入记录。您希望该文件访问得到严格协调。您可以使用一个初始值为1的信号量,并在文件操作代码周围放置两个信号量操作,第一个用于测试和减少信号量的值,第二个用于测试和增加它。首先访问该文件的进程将尝试减少信号量的值,并成功地执行此操作,因此信号量的值现在为0。此进程现在可以继续使用数据文件,但是如果另一个想要使用它的进程现在尝试减少信号量的值,则会失败,因为结果为-1。该进程将被挂起,直到第一个进程完成对数据文件的操作。当第一个进程完成对数据文件的操作后,它将增加信号量的值,使其再次变为1。现在等待的进程可以被唤醒,这次它尝试增加信号量的尝试将成功。 输入图像描述
  • 共享内存:共享内存允许一个或多个进程通过出现在它们所有虚拟地址空间中的内存进行通信。虚拟内存的页面由每个共享进程的页表项引用。它不必在所有进程的虚拟内存中具有相同的地址。与所有 System V IPC 对象一样,对共享内存区域的访问是通过密钥和访问权限检查来控制的。一旦内存被共享,就没有检查进程如何使用它。它们必须依赖其他机制(例如 System V 信号量)来同步访问内存。 enter image description here

摘自 tldp.org


9
这个问题是关于共享内存实现的。你提供了可用IPC机制的概述,其中大部分并不相关,但并没有真正回答问题。此外,“inspired”不是从另一个来源直接复制内容的正确英语单词。你应该清楚地表明你的帖子是引用,并cite the exact source url - Aryeh Leib Taurog

1
在Linux中有两种共享内存。
  1. 如果A和B是父进程和子进程,它们各自使用自己的pte来访问共享内存。共享内存由fork机制共享。所以一切都很好,对吧?(更多细节,请查看内核函数copy_one_pte()及相关函数。)

  2. 如果A和B不是父子关系,它们使用公共密钥来访问共享内存。

假设A通过System V shmget()创建了一个带有密钥的共享内存,相应地,内核会在shmem/tmpfs中为进程A创建一个文件(文件名为"SYSTEMV+key"),这是一个基于内部RAM的文件系统。它由内核挂载(Check shmem_init())。共享内存区域由shmem/tmpfs处理。基本上,当进程A访问共享内存区域时,它由页面错误机制处理。如果进程B想要访问由进程A创建的那个共享内存区域,进程B应该使用与进程A使用的相同密钥的shmget()。然后进程B可以找到文件("SYSTEMV+key")并将其映射到进程B的地址空间中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接