17

在思考了共享内存的整个概念之后,提出了一个问题:

两个进程可以共享同一个共享内存段吗?两个线程可以共享同一个共享内存吗?

想得更清楚一点后,我几乎肯定两个进程可以共享同一个共享内存段,其中第一个是父亲,第二个是儿子,这是用 a 创建的fork(),但是两个线程呢?

谢谢

4

4 回答 4

30

两个进程可以共享同一个共享内存段吗?

是和不是。通常在现代操作系统中,当另一个进程从第一个分叉时,它们共享相同的内存空间,并在所有页面上设置一个写时复制。对任何读写内存页面进行的任何更新都会为该页面制作一个副本,因此将有两个副本,并且该内存页面将不再在父进程和子进程之间共享。这意味着只有只读页面或尚未写入的页面将被共享。

如果一个进程没有从另一个进程派生出来,那么它们通常不会共享任何内存。一个例外是,如果您正在运行同一程序的两个实例,那么它们可能会共享代码,甚至可能共享静态数据段,但不会共享其他页面。另一个是一些操作系统如何允许应用程序共享由多个应用程序加载的动态库的代码页。

还有特定的内存映射调用来共享相同的内存段。该调用指定映射是只读的还是读写的。如何做到这一点非常依赖于操作系统。

两个线程可以共享同一个共享内存吗?

当然。通常,多线程进程内部的所有内存都由所有线程“共享”,除了一些相对较小的每个线程的堆栈空间。这通常是线程的定义,因为它们都在相同的内存空间中运行。

线程还增加了在与处理器/内核相关的高速内存中缓存内存段的复杂性。这个缓存的内存不是共享的,内存页面的更新会根据同步操作刷新到中央存储中。

于 2012-07-19T18:12:59.727 回答
5

一般来说,进程的一个重点是防止内存被共享!在最常见的操作系统上当然可以通过共享内存段进行进程间通信,但默认情况下不存在这种机制。如果幸运的话,未能正确设置和管理共享区域可能会导致 segFault/AV,否则可能会导致 UB。

然而,属于同一进程的线程没有这种硬件内存管理保护,几乎可以共享它们喜欢的任何东西,明显的缺点是它们几乎可以破坏它们喜欢的任何东西。我从来没有真正发现这是一个大问题,尤其是。使用倾向于将指针“结构化”为对象实例的现代 OO 语言(Java、C#、Delphi)。

于 2012-07-19T18:18:44.660 回答
2

是的,两个进程都可以附加到共享内存段。如果不是这样,共享内存段将没有多大用处,因为这是共享内存段背后的基本思想——这就是为什么它是 IPC(进程间通信)的几种形式之一。

同一进程中的两个线程也可以都附加到共享内存段,但鉴于它们已经共享了它们所属进程的整个地址空间,因此可能没有多大意义(尽管有人可能会认为这是提出一个或多或少有效的用例的挑战)。

于 2012-07-19T18:17:37.927 回答
1

一般而言,每个进程占用一个与所有其他进程隔离的内存空间,以避免不必要的交互(包括那些可能代表安全问题的交互)。但是,通常有一种方法可以让进程共享部分内存。有时这样做是为了减少 RAM 占用(VAX/VMS 中的“已安装文件”是/曾经是这样的一个例子)。它也可以是协作进程进行通信的一种非常有效的方式。如何实现/结构化/管理共享(例如父/子)取决于特定操作系统提供的功能和在应用程序代码中实现的设计选择。

在一个进程中,每个线程都可以访问与同一进程的所有其他线程完全相同的内存空间。一个线程唯一对自己独特的是“执行上下文”,其中一部分是它的堆栈(尽管没有什么可以阻止一个线程访问或操作“属于”同一进程的另一个线程的堆栈)。

于 2013-06-23T18:27:01.267 回答