在shmdt()和shmctl(shmid,ipc_RMID,0)之前的进程中访问共享内存

假设我有一个指针*p到先前分配的共享内存

如果其中一个进程调用shmdt()来分离共享内存段,然后尝试分配一个值,例如:

 *p = 0; 

在调用shmctl(shmid, IPC_RMID, 0)进行销毁。

这样做会导致错误? 我无法理解哪些和为什么。

是的,这是一个错误,很可能会导致段错误。

当你调用shmget(2)来分配一个共享内存段时,它不会立即放在你的进程的虚拟地址空间的任何地方。 也就是说,没有可以写入的地址将数据写入段。

shmat(2)是把这个段放到你的进程的地址空间中。 (在System V共享内存的说法中,这被称为附加段,但是这个术语在其他地方并没有太多用处, 映射是比较常见的)。在成功调用shmat() ,段会出现在某个地址,作为shmat()的结果返回。

在先前附加的段上调用shmdt(2)使该段再次从进程的虚拟地址空间中消失。 尝试写入以前映射的一部分的地址是一个错误,因为映射不再存在。 这并不意味着被写入段的数据就会丢失 – 它只是没有映射到任何地方。 您可以重新映射(重新附加)段与另一个调用shmat(2)再次访问数据。

只有在使用shmctl()销毁该段并且IPC_RMID是实际释放的内存(一旦该段不再连接到任何地方)。

为了使事情更具体一些,下面介绍一下如何简单地实现共享内存:

  • shmget()为请求的段分配尽可能多的物理内存。

  • shmat()对MMU进行编程,并在内核中进行设置,以便进程中的某些地址范围映射到该段。

  • shmdt()执行反向操作并删除映射。

  • IPC_RMID shmctl() IPC_RMID释放该段的物理内存(将其标记为空闲)。

作为一个方面说明,可以使用shmat(2)将相同的段映射到地址空间中的多个位置。 这是可能的,因为它纯粹是一个虚拟内存操作。