【发布时间】:2015-05-11 06:17:55
【问题描述】:
假设我有一个指向先前分配的共享内存的指针 *p。
如果其中一个进程调用shmdt() 来分离共享内存段,然后尝试分配一个值,例如:
*p = 0;
在调用shmctl(shmid, IPC_RMID, 0) 进行销毁之前。
这样做会导致错误吗?我很难理解是哪一个以及为什么。
【问题讨论】:
标签: c linux process shared-memory
假设我有一个指向先前分配的共享内存的指针 *p。
如果其中一个进程调用shmdt() 来分离共享内存段,然后尝试分配一个值,例如:
*p = 0;
在调用shmctl(shmid, IPC_RMID, 0) 进行销毁之前。
这样做会导致错误吗?我很难理解是哪一个以及为什么。
【问题讨论】:
标签: c linux process shared-memory
是的,这是一个错误,很可能会导致段错误。
当您调用shmget(2) 分配共享内存段时,它不会立即放在进程的虚拟地址空间中的任何位置。也就是说,没有可以写入的地址会将数据写入段。
shmat(2) 的工作是将段放入(映射)到进程的地址空间中。 (在 System V 共享内存用语中,这称为附加段,但该术语在其他地方使用不多。映射更常见。)在成功调用 @ 987654324@,该段将出现在某个地址,并且该地址作为shmat()的结果返回。
在先前附加的段上调用shmdt(2) 会使该段再次从进程的虚拟地址空间中消失。尝试写入以前属于映射一部分的地址是错误的,因为映射不再存在。然而,这并不意味着写入该段的数据会丢失——它只是没有映射到任何地方。您可以再次调用shmat(2) 重新映射(重新附加)该段以再次访问数据。
只有在您使用shmctl() 和IPC_RMID 销毁段之后,才会真正释放内存(一旦段不再附加到任何地方)。
为了让事情更具体一点,以下是共享内存的简单实现如何在高层次上工作:
shmget() 分配的物理内存与您对该段的请求一样多。
shmat() 对MMU 进行编程并在内核中进行设置,以便进程中的某些地址范围映射到该段。
shmdt() 执行反向操作并删除映射。
shmctl() 和 IPC_RMID 释放段的物理内存(将其标记为空闲)。
附带说明,可以使用shmat(2) 将同一段映射到地址空间中的多个位置。这是可能的,因为它纯粹是一个虚拟内存操作。
【讨论】: