MultiThread编程中是否可以进行死锁恢复?

时间:2010-10-03 18:24:05

标签: multithreading debugging operating-system deadlock

进程有大约10个线程,所有10个线程都进入DEADLOCK状态(假设所有线程都在等待Mutex变量)。

如何从DEADLOCK状态释放进程(线程)? 。 有没有办法杀死优先级较低的线程?(在多进程的情况下,当所有进程都处于死锁状态时,我们可以杀死优先级较低的进程。)

我们可以将该死锁进程附加到调试器并为Mutex变量分配适当的值(假设所有线程都在等待互斥变量MUT,但它的值为0,我们可以通过调试器将MUT值分配给1)。

2 个答案:

答案 0 :(得分:5)

如果应用程序中的每个线程都在等待所有其他线程,并且没有一个线程设置超时,那么你就会被搞砸了。您可能能够在调试器或其他东西中运行应用程序,但通常会出于某种原因获取锁定 - 并且手动强制互斥锁由不合法获取它的线程拥有可能会导致一些大问题(该线程)以前拥有它仍然会尝试释放它,如果互斥锁被意外地拉走,其结果可能是不可预测的。可能导致意外异常,可能导致互斥锁在仍在使用时被解锁。)无论如何它失败了互斥体的整个目的,所以你只是掩盖了一个更大的问题。

有两种常见的解决方案:

  • 不要让线程永远等待,而是设置超时。在像Java这样的语言中,通过synchronizedlock块将互斥体嵌入到语言中稍微有些困难,但它几乎总是可行的。如果您在等待锁定时间超时,请释放您拥有的所有锁定/互斥锁,然后再尝试。

  • 更好,但可能更复杂的是弄清楚为什么一切都在争夺资源并消除这种争论。如果必须锁定,请始终锁定。但是如果在一个互斥锁上有10个线程被阻塞,那么这可能是你的操作被严重分块的线索(即:你的线程在尝试获取锁之前一次做太多或太少),或者没有必要锁定继续。除非必须,否则不要锁定。通过使用专门设计为“无锁”的集合和算法,同时仍提供线程安全性,可以避免某些同步。

答案 1 :(得分:4)

添加另一个答案,因为我不同意cHao之前提出的解决方案 - 分析很好。

首先,为什么我不同意所提供的两种解决方案:

  

减少争用

争用不会导致死锁。这只会导致性能不佳。死锁意味着没有表现。因此,减少争用并不能解决死锁问题。

  

互斥锁超时。

互斥锁保护资源,线程锁定互斥锁,因为它需要资源。超时后,您将无法获取资源,并且您的线程失败。它能解决死锁问题吗?仅当失败的线程释放阻止其他线程的另一个资源时。

但在这种情况下,有一个更好的解决方案。互斥锁应该有一个部分排序。如果至少有一个线程可以同时使用互斥锁A和B,则应该先决定是先获取A还是B,然后坚持使用。这必须是一个传递顺序:如果你在B之前锁定A,在C之前锁定B,那么显然你必须在C之前锁定A.

这是解决死锁的完美解决方案。回顾一下超时的例子:它只有在超时等待A的线程然后释放其对B的锁定时,才能释放另一个在B上等待的线程。在最简单的情况下,该另一个线程本身直接锁定A因此,互斥锁A和B没有正确排序。您应该始终先锁定A或B.

超时情况也可能是循环订单问题的结果;一个线程锁定A然后B,另一个B然后是C,第三个C然后是A,当每个线程拥有一个锁时发生死锁。解决方案再次相同;订购锁。

或者说,互斥锁定顺序可以通过有向图来描述。如果线程在B之前锁定A,则会出现从A到B的弧。如果有向图是循环的,则会出现死锁,然后该循环的弧就是死锁线程。

这个理论可能有点复杂,但有一些简单的见解可以找到。例如,从图论中,我们知道树是非循环图。因此,“叶子互斥体”(总是被锁定最后的那些)和“根互斥体”(那些总是被锁定第一次)都不会导致死锁。叶子互斥体被排除,因为没有线程阻塞它们,并且根互斥锁被排除,因为保存它们的线程将能够在适当的时间锁定所有后续互斥锁。