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