【问题标题】:Management of Unix Shared MemoryUnix共享内存的管理
【发布时间】:2012-04-15 07:47:55
【问题描述】:

我们知道,Windows 中的共享内存是通过系统页面文件支持的内存映射文件实现的,并且始终以引用计数的方式进行管理(http://msdn.microsoft.com/en-us/library/windows /desktop/aa366537(v=vs.85).aspx)。

我想知道 Unix 是否以类似的方式做到这一点。有人(http://stackoverflow.com/q/4278391/939142)说 Unix 也以引用计数的方式管理 shm。我在 Mac OS X 上做了一个实验,发现不是这样。

使用最后提供的代码,编译两个程序:主机和客户端。类型

./host 

创建一个 shm,在其第一个地址写入 (int) 10,然后退出。然后输入

./client <shmid>

检查附加到创建的 shm 的 shm 段,打印第一个 int,然后退出。

请注意,我们使用 shmat 和 shmdt 来连接/断开 shm,并使用 shmget 来创建 shm。

要销毁 shm,我们必须使用 shmctl 手动完成。

结论: shm 在 Unix 中不作为引用计数进行管理,至少对于 Mac OS X 而言

/************************** host.c ****************************/

#include <stdio.h>
#include <sys/shm.h>
#include <mach/vm_param.h>
#include <assert.h>

int
main(int argc, char** argv)
{
int value = 10;
int id;
void* ptr;
    /* create a new shm */
id = shmget(IPC_PRIVATE, PAGE_SIZE, IPC_CREAT | 0666);
assert(id != -1);
    /* attach to the new shm */
ptr = shmat(id, (const void*) NULL, 0);
assert((int*) ptr != -1);
    /* print the id so that client can use */
printf("shm id = %ld\n", id);
printf("address of id = %ld, length = %ld\n", ptr, PAGE_SIZE);
((int*) ptr)[0] = value;
printf("value at address %ld = %ld\n", ptr, *(int*) ptr);
/* detach from the shm and exit */
    shmdt((const void*) ptr);
return 0;
}


/************************** host.c ****************************/

#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include "assert.h"
#include <mach/vm_param.h>

int
main(int argc, char** argv)
{
void* ptr;
int id = atoi(argv[1]);
assert(id != -1);
    /* attach to the shm */
ptr = shmat(id, NULL, 0);
assert(ptr != -1);
printf("value at ptr = %ld = %ld\n", ptr, *(int*) ptr);
shmdt((const void*) ptr);
return 0;
}

【问题讨论】:

    标签: unix shared-memory


    【解决方案1】:

    它不是纯粹的引用计数。根据 shmctl(2):

    IPC_RMID:标记要销毁的段。该段将只 在最后一个进程将其分离后实际上被销毁 (即,当关联结构的 shm_nattch 成员 shmid_ds 为零)。调用者必须是所有者或创建者,

    这意味着:IPC_RMID 不会立即删除,而只会在下次引用计数降至零之后。

    这使您可以使用同一工具实现多个目标:

    • 服务器创建、附加并立即设置RMID 的服务器/客户端方法。然后,只要服务器在这里,客户端就可以连接。如果服务器宕机,客户端应该断开连接,操作系统会清理资源。

    • 或“消息”方法:有人写消息,将其固定到已知位置。之后其他人可以来,寻找消息并采取相应的行动。这就是你所做的。当然,这种方法对资源垃圾更开放。但也有这方面的用例。

    【讨论】:

    • 甜蜜的解释。非常感谢。
    • 我刚刚发现你的manage来自Linux,并且“mark”行为不能移植到其他*nix系统。我在 Mac OS X 和 Debian 上尝试了另一个实验。在 Mac OS X 中,shm 在有效的 IPC_RMID 命令后立即被删除。
    • @stoictopia:根据 Richard Stevens 的“Unix 环境中的高级编程”一书,Linux 的IPC_RMID 行为符合标准,但有一个例外:Linux 允许重新连接 IPC_RMID之后。其他操作系统没有。但是在 all 的情况下,shm 段对于所有已经附加的人来说仍然存在。这意味着您不能简单地从带有IPC_RMID 的进程中拉出地毯。我认为您将这两种不同的东西合二为一。
    • 我明白了。我可以通过 ipcs 查看打开的 shm。在这两个系统上,shm 仍然连接在 IPC_RMID 之后和最后一个 shmdt 之前。但是,至少还有一个区别:在 Debian 上,refcount = 1 在 IPC_RMID 之后直到最后一个 shmdt 仍然有效,而在 OSX 上,refcount 在 IPC_RMID 之后不再有效。
    • 正如stackoverflow.com/a/42479369/2732969 中所述,不仅仅是 Linux 具有“在IPC_RMID 之后附加”语义。其他一些操作系统(版本 11 的 FreeBSD)甚至已经从它们所拥有的转换为 Linux 风格的行为,但遗憾的是 macOS(至少到 10.15)不在此类别中。
    猜你喜欢
    • 1970-01-01
    • 2013-07-11
    • 2011-01-14
    • 1970-01-01
    • 2019-04-05
    • 2015-06-01
    • 2012-10-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多