1

使用 System V 共享内存 IPC 需要调用以下两个函数:

int shmget(key_t key, size_t size, int shmflg);
void *shmat(int shmid, const void *shmaddr, int shmflg);

为什么它们被设计成独立的,而不是有一个接受这些参数的函数,执行两个函数并简单地返回地址?

我们可以将文件视为类比。open在一个字符串(文件路径)上给我们一个文件描述符,我们用它来读/写文件。完成后我们close在文件描述符上。这种设计看起来很自然,我们不必open用字符串来获取描述符,然后再去attach描述符。

作为我想到的一个例子,看看FreeBSD sendmail shared memory implementation

这种分离(shm_openmmap)也存在于 POSIX 共享内存中,但原因是在实现mmap之前存在shm_open并且可以重用,并且mmap需要描述符(来源:UNIX Network Programming Vol. 2, R. Stevens, Chapter 13, page 326)。

4

2 回答 2

0

共享内存可能是允许 IPC 的最快方式之一,因为不需要复制数据,但与之相关的问题是同步多个线程之间的访问。您可以使用信号量或记录锁来做到这一点,我们最终在 unix 中使用共享内存中的后者,即使它们不如它们简单高效,系统清理得很好,而且您不需要一些闪亮的东西信号量带来。让我们看看这些是如何工作的,以了解它们为何如此实现。

linux内核(http://www.tldp.org/LDP/lpg/node68.html)使用的shmid_ds进来,shm_nattch是当前附件的无符号整数计数器。shmget 为您获取一个 shm id 并设置诸如 ipc_perm 、日期、pid、atime ctime、段大小请求(shm_segsz)之类的内容,然后 shmctl 启动并使用 IPC_STAT、IPC_RMID、IPC_SET 为 ipc 做一些事情,例如设置 perms、获取或删除段的 shm_id 甚至锁定或解锁它。

段准备好后,进程使用 shmat 附加到其地址空间,具体取决于标志和地址参数。一旦它附加内核就会增加 shm_nattch。分离时,我们调用 shmdt 来分离。标识符和相关数据结构的删除不是自动的,某些进程必须使用 IPC_RMID 调用 shmctl 并取决于 shm_perm

正如您所看到的,这与使用信号量的方式非常相似,并且实现是有意义的。

于 2013-11-07T19:48:30.383 回答
0

我能想到的一个可能原因是:(来自shmget 的联机帮助页

  • 在 fork(2) 之后,子进程继承了附加的共享内存段。
  • 在 execve(2) 之后,所有附加的共享内存段都与进程分离。
  • 在 _exit(2) 时,所有附加的共享内存段都与进程分离。

好吧,从技术上讲,附加和分离是在 shmget 期间保留的共享内存段上的基本引用计数。

分配共享内存段的功能,通过 shmget 和引用计数(向上或向下,分别通过 shmat 和 shmdt)是独立的,因此代码可以在 fork 和 exec 期间重用。

如果它们都被打包到同一个函数中,那么无论如何您都需要一个单独的函数,它只是进行引用计数(在 fork/exec 期间调用)。所以,我觉得这个设计纯粹是为了促进代码复用,避免代码重复。

于 2013-11-07T22:22:48.293 回答