进程结束/死亡时的共享POSIX对象清理

4
有没有办法在进程崩溃时执行POSIX共享同步对象清理?最理想的是解锁POSIX信号量,但自动“收集”的队列/共享内存区域也很好。另一件需要注意的事情是,由于SIGKILL无法被捕获,通常不能使用信号处理程序。
我只看到一种替代方案:一个外部守护进程,接受订阅和“保持活动”请求,作为看门狗工作,因此如果没有关于某个对象的通知,它可以根据注册的策略关闭/解锁对象。
有没有更好的替代方案/建议?我以前从未认真使用过POSIX共享对象(套接字对我的所有需求都足够了,并且在我看来更有用),并且我没有找到任何适用的文章。我很乐意在这里使用套接字,但由于历史原因无法使用。
3个回答

3
与其使用信号量来协调进程,您可以使用文件锁定。文件锁的一个巨大优势是如果进程终止,则会释放锁。您可以将每个信号量映射到共享文件中的一个字节的锁上,并知道锁将在退出时被释放;在大多数Unix版本中,您锁定的字节甚至不必存在。Marc Rochkind的《高级Unix编程》第1版中有此代码,但不知道最新的第2版是否包含该代码。

你推荐的书真的很好。lockf() 至少涵盖了原始问题(信号量死锁)中最危险的部分,我构建的原型运行良好。 - Roman Nikitchenko
顺便提一下,lockf() 可以使用第三个参数设置为 0(整个文件)。这样就不需要任何实际的字节存在。至少在 Linux 上是这样的。 - Roman Nikitchenko

3
我知道这个问题很旧了,但另一个很好的解决方案是 POSIX 鲁棒互斥锁。当所有者死亡时,它们会自动解锁并进入“不一致标志”状态,下一个尝试锁定互斥锁的线程会得到一个 EOWNERDEAD 错误,但成功成为互斥锁的新所有者。然后可以清理互斥锁所保护的任何状态(由于以前所有者的异步终止可能处于非常糟糕的不一致状态!),并在解锁之前将互斥锁标记为一致状态。
请参阅此处有关鲁棒互斥锁的文档:

http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_lock.html


2
通常的方法是使用信号处理程序。只需捕获信号并调用清理函数即可。
但你的看门狗守护进程也有一些优点。它肯定会使系统更简单易懂、易管理。为了更方便地进行管理,你的应用程序应该在它没有运行时启动守护进程,并且守护进程应该能够清除上次崩溃留下的任何残留物。

问题在于我们应该即使在收到SIGKILL信号时也要保持运行。我根据您的答案进行了修改。关于守护进程,我更喜欢系统服务实现,以便能够跟踪依赖项。 - Roman Nikitchenko
你不应该试图捕获SIGKILL信号。如果你的代码中有一个bug,那么它将无法终止。所以你不想要这种情况发生。你需要做的是遍历所有资源并检查它们是否仍在使用中。大多数使用SHM的应用程序都提供了清理所有共享资源的工具。我建议自动化这一步骤。 - Aaron Digulla
1
不仅是“你不应该” - 你不能。http://linux.die.net/man/2/signal “信号SIGKILL和SIGSTOP无法被捕获或忽略。” - ephemient
抱歉,我把SIGINT(也称为Ctrl-C)和SIGTERMkill命令)搞混了。 - Aaron Digulla
是的,我知道我不能捕获SIGKILL和SIGSTOP信号,我只是指出即使有人使用SIGKILL(例如)杀死了某个进程,这个解决方案也应该保持一致。尽管如此,信号处理程序至少应该包括共享资源的释放,对于我们可以做到的情况。你是正确的。 - Roman Nikitchenko
2
你必须在程序启动时释放资源!听起来很疯狂,我知道。原因是在你有机会清理之前,可能会强制将你的进程从系统中移除。在这种情况下,在启动期间分配SHM将失败(因为它们仍然存在)。因此,你必须执行两次操作:在启动时,首先清理所有东西,然后重新分配它。在关闭时,只需解除分配即可。 - Aaron Digulla

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接