如何正确清理和重用 SysV 共享内存段? [英] How do you correctly cleanup and re-use SysV shared memory segments?

查看:71
本文介绍了如何正确清理和重用 SysV 共享内存段?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在为使用 Linux SysV SHM 接口的 API 编写一些粗糙的测试代码.即 ftok(), shmget(), shmctl(), shmat()

I have been writing some gnarly test code for an API that uses the Linux SysV SHM interface. i.e. ftok(), shmget(), shmctl(), shmat()

不幸的是,我不能随意更改此界面(例如使用 shm_open() 代替 或从轨道上将其炸毁).

Unfortunately I am not free to alter this interface (for example to use shm_open() instead or nuke it from orbit).

我通过集成测试发现了一个错误,它使用共享内存生成两个不相关的进程,因为它没有使用 shmdt() 清理共享内存段.我进一步发现约定要使用:

I discovered a bug via an integration test which spawns two unrelated processes using the shared memory in that it was not cleaning up shared memory segments using shmdt(). I further discovered that the convention is to use:

shmctl(segmentId, IPC_RMID, 0);

告诉系统一旦所有进程都分离,就可以删除该段.将此添加到集成测试中修复了共享内存未清理的错误.

to tell the system that the segment can be deleted once all processes have detached. Adding this to the integration tests fixed the bug that the shared memory was not cleaned up.

使用 ipcs -m 查看段,您可以看到它们现在被标记为dest".

Looking at segments using ipcs -m you can see they are now marked "dest".

我还创建了较低级别的单元"测试,这些测试通过派生子进程来创建共享内存来工作.尝试对测试代码应用相同的更正我有一些奇怪的观察:

I have also created lower-level 'unit' tests which work by forking a child process to create the shared memory. Attempting to apply the same correction to the test code I have some strange observations:

  • 如果我做正确的事情并添加对 shmctl(segmentId, IPC_RMID) 的调用,测试将停止工作.

  • If I do the right thing and add calls to shmctl(segmentId, IPC_RMID) the tests stop working.

如果我删除此类调用,测试将重新开始工作.(目前我的解决方案是不在单元测试代码中使用 IPC_RMID)

If I remove such calls the tests start working again. (for now my solution is simply not to use IPC_RMID in the unit test code)

我不确定这是否是问题所在,但由于 ftok() 容易发生冲突,因此在进一步调查后,在先前的测试删除后,某些测试使用了相同的 ID.不过,并非每次失败都如此.

I'm not sure if this is the problem but, investigating further due to ftok() being collision prone the same Id is used for some tests after a previous test has deleted it. This is not the case for every failure though.

如果我从 O_CREAT 更改为 O_CREAT|O_EXCL 打开重新使用相同的令牌失败与 EEXIST.(建议'dest'段在某种意义上仍然存在并且可以重复使用)

If I change from O_CREAT to O_CREAT|O_EXCL opening re-using the same token fails with EEXIST. (suggesting 'dest' segments still exist in some sense and can be re-used)

我还注意到,通过运行许多测试,我有相当数量的 shm 段被列为dest".但是 nattach=2 意味着两个进程未能调用 shmdt().如果我列出据称创建它并上次使用 ipcs -mp 使用它的 pid,它们不是创建或使用它的进程.相反,它们属于诸如 Firefox 之类的东西,这有点令人困惑!我不明白这个.据推测,它们会在重新启动时消失,但它们似乎与此问题没有直接关系.我认为在我修复缺失的 shmdt() 和 shmctl(IPC_RMID) 问题之前,这些已经扼杀了早期的集成测试.

I also notice that from running many tests I have a fair number of shm segments listed as "dest" but with nattach=2 meaning two processes failed to call shmdt(). If I list the pids that supposedly created it and last used it using ipcs -mp they are not the processes that created or used it. Instead they belong to things like firefox which is just slightly confusing! I don't understand this. Presumably they will disappear on reboot but they don't seem directly related to this issue. I think these came killing the earlier integration tests before I fixed the missing shmdt() and shmctl(IPC_RMID) issues.

ipcs -m 列出的许多段的密钥为 0x00000000,这似乎很可疑.毫无疑问,这些是私人部分.

问 (sysV) SHM 在父进程和子进程的上下文中的工作方式是否有什么特别之处,这意味着 IPC_RMID 的行为不同,或者不需要?

Q Is there something special about how (sysV) SHM works in the context of parent and child processes which means the IPC_RMID behaves differently and or is not required?

Q 在子进程中使用 IPC_RMID '删除'段 ID 后,是否有编程方法可以安全地重新使用它?

Q Is there programmatic way to make it safe to re-use a segment Id after having 'removed' it using IPC_RMID a short while previously in a child process?

Q 有没有办法强制删除(取消附加/删除)ipcs -m"中标记为 dest 的段?无需重启?(在操作系统层面)

Q Is there a way to force removal (unattach / delete) the segments marked dest in "ipcs -m" without rebooting? (at the OS level)

Q 是ipcs -pm";显示实际的 pid 还是别的什么?有没有另一种方法可以找出系统认为真正仍然附加的东西?(我相信没有什么是因为我使用 SHM 界面在所有东西上都使用了 kill -9)

Q Is "ipcs -pm" displaying actual pid's or something else? Is there another way to find out what the system thinks is really still attached? (I believe nothing is as I used kill -9 on everything using the SHM interface)

Q 有没有办法强制分离进程,就像调用了 shmdt() 一样?

Q Is there a way to force detach a process as if shmdt() has been called?

推荐答案

我被误导,认为只要指定为所有者的进程附加到共享内存,就调用 shmctl(segmentId, IPC_RMID) 是正确的形式.

I was mislead into thinking it was proper form to call shmctl(segmentId, IPC_RMID) as soon as the process designated as the owner has attached to the shared memory.

事实上,在所有进程都已附加之前,不应调用 IPC_RMID.

In fact IPC_RMID should not be called until all processes have attached.

部分答案在这里:

https://comp.unix.programmer.narkive.com/iLg3PhfZ/shmctl-ipc-rmid-oddity

似乎 IPC_RMID 将段设置为私有,以便没有新进程可以附加到它.

It seems that IPC_RMID sets the segment to private so that no new processes can attach to it.

一种保证唯一段的方法是故意使用 IPC_PRIVATE 开始:

A way of guaranteeing a unique segment is deliberately using IPC_PRIVATE to start with:

id = shmget(IPC_PRIVATE, IPC_CREAT | mode);

这也避免了需要使用 ftok() 和与另一个段冲突的风险.不幸的是,我不能在这里使用它,因为接口基于使用 ftok() 识别段.至少我明白这里的问题.

This also avoids the need to use ftok() and risk colliding with another segment. Unfortunately I cannot use that here as the interface is predicated on identifying the segment with ftok(). At least I understand the issue here.

更聪明的人可能会在重新使用之前以更好的方式进行清理.

Someone wiser may be able to chip in with better ways of cleaning up before re-use.

另见 https://www.linuxquestions.org/questions/programming-9/shmctl-ipc_rmid-precludes-further-attachments-574636/

这篇关于如何正确清理和重用 SysV 共享内存段?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆