在shmdt()之后和shmctl之前访问共享内存(shmid,ipc_RMID,0)

时间:2015-03-09 22:40:58

标签: c linux process shared-memory

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

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

*p = 0;

在致电shmctl(shmid, IPC_RMID, 0)进行销毁之前。

这样做会导致错误吗?我无法理解哪些以及原因。

1 个答案:

答案 0 :(得分:4)

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

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

shmat(2)的工作是将段(映射)放入流程的地址空间。 (在System V共享内存的说法中,这称为附加段,但该术语在其他地方并未使用。映射更常见。)成功调用后到shmat(),该细分将显示在某个地址,该地址将作为shmat()的结果返回。

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

只有在使用shmctl()IPC_RMID销毁片段后才会释放实际释放的内存(一旦该片段不再附加到任何位置)。

为了使事情变得更具体,以下是共享内存的简单实现如何在高层次上发挥作用:

  • shmget()分配您为该段请求的物理内存。

  • shmat()MMU进行编程并在内核中进行设置,以便流程中的某些地址范围映射到细分受众群。

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

  • 带有shmctl()
  • IPC_RMID会释放该段的物理内存(将其标记为免费)。

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