假设我有一个指针*p
到先前分配的共享内存。
如果其中一个进程调用shmdt()
来分离共享内存段,然后尝试分配一个值,例如:
*p = 0;
在致电shmctl(shmid, IPC_RMID, 0)
进行销毁之前。
这样做会导致错误吗?我无法理解哪些以及原因。
答案 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)
将同一段映射到地址空间中的多个位置。这是可能的,因为它纯粹是虚拟内存操作。