假设我有一个指针*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)
将相同的段映射到地址空间中的多个位置。 这是可能的,因为它纯粹是一个虚拟内存操作。