当Linux杀死一个进程时,它是否释放自旋锁/信号量?

9

如果一个进程持有一些自旋锁或信号量,并且意外退出(例如,被Linux杀死),那么Linux会正确释放这些锁吗? 如果Linux没有执行此操作,为什么呢?


1
如果你对于Linux架构中的同步机制感兴趣,那么你可能想要了解一下futex系统调用的工作原理(“man 7 futex”,“man 2 futex”)。在阻塞情况下,phtread_mutex和sem_wait都是通过futex实现的。 - Andrew Tomazos
1个回答

11
这取决于你所谈论的锁的类型。如果你谈论任何内核内部锁,它们将根据需要被释放(否则系统很快会崩溃)。一般来说,这些锁不是由进程本身拥有的,而是由一些内部内核工作流拥有的,并且通常在进程返回用户空间后就不再保持锁定状态了。
但请注意,如果内核在你发出kill命令时已经死锁,那么该进程可能无法被杀掉。进程终止是作为信号处理路径的一部分执行的,该路径从内核到用户空间返回转换代码中调用。如果进程正在等待内核自旋锁,则永远无法到达返回代码,因此该进程将无法退出。
此外,如果进程因内核OOPS而被杀死,那么所有的赌注都是无效的——内核已经处于不一致状态,而OOPS退出代码并没有非常努力地清理内核线程可能在当时持有的任何锁。
如果你在谈论任何类型的用户空间自旋锁或信号量(包括IPC信号量的sem_*系列),那么不会被释放,因为没有锁所有权的概念。
如果你在谈论的是文件锁的flock系列,或fcntl(F_SETLK, ...)建议性锁定,则当该进程中绑定到文件的任何文件描述符关闭时,它们将自动释放。由于这个原因,在大多数情况下使用flock是一个坏主意,但是如果进程被杀死,它将被释放。

如果你在谈论一个进程内的pthread_mutex,那么这个问题就没有意义了,因为当进程终止时,互斥锁也将随之消失。

如果你在谈论一个共享内存段中的共享pthread_mutex(即使用pthread_mutexattr_setpshared使其可共享的互斥锁),只有当它同时被标记为强壮互斥锁(使用pthread_mutexattr_setrobust)时,它才会在进程结束时自动释放。但是,在重新使用之前,必须将其标记为一致;请参阅pthread_mutex_consistent手册页以获取详细信息。


非常感谢。我正在谈论内核内部锁,因为我们想要解决系统死锁错误。在某些错误发生时,这些种类的锁是具有影响力的,特别是自旋锁(非常破坏性!!) - silverbullettt
@silverbullet,如果你的内核死锁了,你实际上无法杀死涉及的进程 - 杀死一个进程需要从内核转换退出,因为SIGKILL信号在内核到用户空间退出代码路径中被处理。由于进程已经死锁,它甚至无法走到那一步。 - bdonlan
是的,信号只会在内核到用户空间退出代码路径中处理,因此我们计划采取非常规手段——Linux内核提供了force_sig()函数,如果该函数能够按照我们的期望工作(向进程发送信号并唤醒它),那么我们就解决了这个问题。 - silverbullettt
@silverbullet,不行,那样做不起作用。线程(或进程)退出总是发生在绑定到该线程的内核线程中,以确保释放所有锁并使其操作的任何数据结构处于干净状态。force_sig仅绕过用户空间信号忽略;它仍然必须经过所有其他正常处理。这里唯一真正的解决方案是首先修复导致问题的死锁。 - bdonlan
如果我向一个进程发送SIGKILL信号,然后立即使用wake_up_process()将其唤醒,这样会起作用吗? - silverbullettt
如果它正在等待自旋锁,那么它已经醒来了。如果它正在等待内核信号量或其他东西,它将立即回到睡眠状态。一旦在内核中出现死锁,你就注定要失败了。更重要的是,该锁可能保护着某些重要的东西 - 如果你随意打破锁,你会留下一些损坏,以后你还会遇到麻烦。 - bdonlan

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