如何解决您如何正确清理和重用 SysV 共享内存段?
我一直在为使用 Linux SysV SHM 接口的 API 编写一些粗糙的测试代码。 即 ftok(),shmget(),shmctl(),shmat()
不幸的是,我不能随意更改此界面(例如使用 shm_open() 代替 或从轨道上将其炸毁)。
我通过集成测试发现了一个错误,它使用共享内存生成两个不相关的进程,因为它没有使用 shmdt() 清理共享内存段。我进一步发现 约定要使用:
shmctl(segmentId,IPC_RMID,0);
告诉系统一旦所有进程都分离,就可以删除该段。 将此添加到集成测试中修复了共享内存未清理的错误。
使用 ipcs -m 查看段,您可以看到它们现在被标记为“dest”。
我还创建了较低级别的“单元”测试,这些测试通过派生子进程来创建共享内存来工作。 尝试对测试代码应用相同的更正我有一些奇怪的观察:
-
我不确定这是否是问题所在,但由于 ftok() 容易发生冲突,因此在进一步调查后,在先前的测试删除后,某些测试使用了相同的 ID。 不过,并非每次失败都如此。
-
如果我从 O_CREAT 更改为 O_CREAT|O_EXCL 打开重新使用相同的令牌失败与 EEXIST。 (建议'dest'段在某种意义上仍然存在并且可以重复使用)
-
我还注意到,通过运行许多测试,我将相当数量的 shm 段列为“dest”,但 nattach=2 意味着两个进程未能调用 shmdt()。如果我列出据称创建它并上次使用 ipcs -mp 使用它的 pid,它们不是创建或使用它的进程。相反,它们属于诸如 Firefox 之类的东西,这有点令人困惑! 我不明白这个。据推测,它们会在重新启动时消失,但它们似乎与此问题没有直接关系。 我认为在我修复缺失的 shmdt() 和 shmctl(IPC_RMID) 问题之前,这些已经扼杀了早期的集成测试。
-
ipcs -m 列出的许多段的密钥为 0x00000000,这似乎很可疑。毫无疑问,这些是私人部分。
问 (sysV) SHM 在父进程和子进程的上下文中的工作方式是否有什么特别之处,这意味着 IPC_RMID 的行为不同,或者不需要?
Q 在子进程中使用 IPC_RMID '删除'段 ID 后,是否有编程方法可以安全地重新使用它?
Q 有没有办法在不重新启动的情况下强制删除(取消附加/删除)“ipcs -m”中标记为 dest 的段? (在操作系统层面)
问“ipcs -pm”是显示实际的pid还是别的什么? 有没有另一种方法可以找出系统认为真正仍然附加的东西? (我相信没有什么是因为我在使用 SHM 界面的所有东西上都使用了 kill -9)
Q 有没有办法强制分离进程,就像调用了 shmdt() 一样?
解决方法
我被误导,认为一旦指定为所有者的进程附加到共享内存,就调用 shmctl(segmentId,IPC_RMID) 是正确的形式。
事实上,在所有进程都已附加之前,不应调用 IPC_RMID。
部分答案在这里:
https://comp.unix.programmer.narkive.com/iLg3PhfZ/shmctl-ipc-rmid-oddity
似乎 IPC_RMID 将段设置为私有,以便没有新进程可以附加到它。
一种保证唯一段的方法是故意使用 IPC_PRIVATE 开始:
id = shmget(IPC_PRIVATE,IPC_CREAT | mode);
这也避免了需要使用 ftok() 和与另一个段冲突的风险。 不幸的是,我不能在这里使用它,因为接口是基于使用 ftok() 识别段的。至少我明白这里的问题。
更聪明的人可能会在重新使用之前以更好的方式进行清理。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。