多线程WIN32程序如何检查死锁(二)-检查死锁的策略

多线程应用程序中检查死锁的方法

WIN32 API的好的特性就是能够让你所有可能引起死锁的资源。在上面的WINDOWS3.1的例子中,硬盘驱动器制造商,应用程序员,WINDOWS开发人员都不可能预测到死锁,因为这个死锁包含了几个软件部分,而且软件内部的功能对其他部分的作者来说是未知的,但如果把他们放在一起,他们就能够让系统挂起。

然而在WIN32 API中,所有的同步对象只能在本地工作,也就是说,他们不能影响那些决定共享他们的线程,因此也不存在能够声明在VMM OS/2中的全局关键代码段,从而被系统中的其他线程挂起。在NT上,由于你编写代码的粗心,你可能被死锁的一个或几个应用程序,但其他的系统程序不会受影响,这增加了安全和可靠性。

基本上,检查死锁使用两种方法的一种:程序死锁后的检查和不变的检查;死锁后的策略在前面已经解释了:发布一个产品,等到死锁发生以后来,而通过预先设置的字段来指示可能的死锁条件,然后在下一个版本中修改(我敢确信这不是所有公司都使用的深思熟虑的好办法,它有一个严重的副作用就是,不能有足够的时间来做正式的分析)。

为了解析不变的方法,让我们来回到GOOFY例子,即使不运行GOOFY,我们也能够立即检查可能出现的死锁,我们所需要的就是证明死锁发生的条件,确切的说是当一个线程拥有关键代码段1并等待关键代码段2,这个时候另外一个线程拥有关键代码段2却等待关键代码段1。我们很容易的就可以证明GOOFY中存在我们描述的死锁条件,但相反的情况,也就是我们很难证明一个线程不包含死锁条件。让我们来看看GOOFY2,是对GOOFY的一个修改版。GOOFY2看起来与GOOFY非常的相似,仅仅在生命关键代码段的时候以嵌入式的方式(声明A,声明B,释放B,释放A),两个线程都是首先声明关键段1然后声明关键段2,有效地复制了关键段1。这从变成的角度来看没有什么意义,但它符合我们前面描述的观点(这也是我为什么叫他做GOOFY的原因)。

Long WINAPI ThreadFn(long lParam)

{

  while(TRUE)

  {EnterCriticalSection(&cs1);       // change!

   printf("/nThread2 has entered Critical Section 1 but not 2.");

   EnterCriticalSection(&cs2);       // change!

   printf("/nThread2 has entered Critical Section 1 and 2!");

   LeaveCriticalSection(&cs2);       // change!

   printf("/nThread2 has left Critical Section 2 but still owns 1.");

   LeaveCriticalSection(&cs1);       // change!  

   printf("/nThread2 has left both critical sections...");

   Sleep(20);

  };

}

我们强烈的感觉GOOFY2不会死锁,但我们能除了感觉能做到更好吗?我们能证明GOOFY2不会死锁吗?或者不使用许多希腊字母和限于你航空技术研究生学位的论证?

让我们对GOOFY2的控制流程做说明。首先,定义关键段是要不关键段1是自由的,要不线程1或线程已经声明了关键段1,同样,因为关键段1也仅仅在他是自由的时候才能被声明,并且关键段1唯一自由的地方就是两个线程都各自执行它while循环前面的部分,我们可以安全的说,关键段1是自由的或者一个线程已经拥有了它,并且另一个线程必须执行while循环到EnterCriticalSection(&cs1)之间的代码,同时等待声明关键段1。同样关键段2只能在关键段1之后开始声明,无论在什么时候如果拥有关键段2,就必须拥有前面的关键段1,拥有关键段2的线程必须执行EnterCriticalSection(&cs2)EnterCriticalSection(&cs2) 之间的代码,而其他的线程同时只能执行while循环前面的代码并等待关键段。

现在死锁发生的唯一条件就是如果线程A被另外一个线程B拥有的资源挂起,而同时A轮流拥有一个B等待的关键段。然后,从我们的直觉来判断,一旦任何线程拥有了任何关键段,我们可以断定,其他的线程必须等待关键段1,因此,线程要么拥有一个关键段,要么就没有,从而因此两个线程各自拥有一个关键段的情况不会出现(死锁的必要条件)。

结束了吗?是的,除了我们必须证明我们的直觉是正确的之外,我们将来需要回忆。如果你已经遵从这个论证,你可能在毕业报告上面得到800+的分数。

你可能不知道,上面的讨论实际上是有相当的学术称谓“不变的分析”,你可能记得,我们讨论的在多线程应用程序中检查死锁的第二种方法。

不管两个线程处在什么状态,我们决定的一些关于应用的语句一直保持真值。因为这个特性

这些语句被叫做不变的(在拉丁语中是“不改变”)。不变式有资格成为计算机科学家最爱玩具的前10位之一,因为你可以使用他们来做许多很酷的事情。在多线程应用程序中,你能够很好的使用检测死锁:当我们讨论GOOFY2的时候所做的是死锁的表现的最基本的描述,然后讨论这样一个死锁将违背一些不变量,因此不会发生。

如果有这样一个程序,我们输入一个应用程序,然后它告诉我们所有的不变量,和程序中存在的死锁不是更好?那样我们就不需要非要去寻找不变量了(同样冒着忘了或误解的这些不变量的风险)并且花费一页页的争论为什么程序能或不能死锁。这样的程序(让我们做下梦,假定它存在,叫做DEADLOCOP)可能是一个多媒体程序并且脱口说出“也,你也许想你是一个好的程序员,但是我告诉你,你给我的程序将比你说的速度更快的崩溃 'Wazoo' take a(用户双击鼠标,DEADLOCOP终止了)

是的,的确伟大。并且猜猜DEADLOCOP被部分实现的功能。我说部分地,是因为通过计算机程序来有效地回答检查死锁所牵涉的问题太多了;然而其他的就是既不可决定的又是不能有效计算的了。让我们列举并评论这些理论计算机科学为此目的而衍生的法则:

1.对于一个给定的应用程序(或一系列)的任何状态来说,都能够用来决定系统是否死锁。请回想一个可能出现被死锁的系统。使用所谓的任何给定状态的资源分配图(RAG),它能被用来检查这个状态能够构成死锁。我们稍后将介绍资源分配图。

2.不变量能被计算在本章的后面我们将着眼于计算不变量的技术。这里的问题是计算可能不是很有效。应该被注意的是单线程的不变量不能被计算。这乍听起来有点奇怪,我们认为一个多线程的应用程序是应用程序更难,因为它比但线程的更复杂!我们正在干什么?

重点是多线程中的一个不变量与单线程中的不变量有点不同。后者,我们关心的是变量被看做是内存的状态,例如变量i的值是变量j的两倍,变量p和变量q的值加起来总是7,而多线程中的不变量指的线程的状态,例如如果一个线程1拥有资源2,而另外一个线程一个线程在他们各自的代码段 34。如果我们希望多线程应用程序的不变量也与他们各自的计算状态一体化的信息,例如他们的变量值那问题就变成不可决定的了。

3.一个被标示为死锁的情况是否能够得到被给定的初始状态是可以判定的。然而计算并不是非常有效,它可能要花更长的时间来得到结果,发挥你的聪明才智而不是机械的算法描述出它可能更有效。

从而,尽管DEADLOCOP有可能被写出来,但它并不能非常有效的工作。在某种意义上,着手于一个实现DEADLOCOP的正式框架将更值得,因为不但这样可以最终引导我们通向更先进版的DEADLOCOP,而且它会给我们一个非常清晰的理解,理解我们的多线程应用程序所做的和怎么做的。在下一节,我将带你进入PETRI网络的精彩旅程,希望使你相信为你的应用程序带来些与以前的不同--也就是圆、矩形和箭头的集合。

不管两个线程处在什么状态,我们决定的一些关于应用的语句一直保持真值。因为这个特性

这些语句被叫做不变的(在拉丁语中是“不改变”)。不变式有资格成为计算机科学家最爱玩具的前10位之一,因为你可以使用他们来做许多很酷的事情。在多线程应用程序中,你能够很好的使用检测死锁:当我们讨论GOOFY2的时候所做的是死锁的表现的最基本的描述,然后讨论这样一个死锁将违背一些不变量,因此不会发生。

如果有这样一个程序,我们输入一个应用程序,然后它告诉我们所有的不变量,和程序中存在的死锁不是更好?那样我们就不需要非要去寻找不变量了(同样冒着忘了或误解的这些不变量的风险)并且花费一页页的争论为什么程序能或不能死锁。这样的程序(让我们做下梦,假定它存在,叫做DEADLOCOP)可能是一个多媒体程序并且脱口说出“也,你也许想你是一个好的程序员,但是我告诉你,你给我的程序将比你说的速度更快的崩溃 'Wazoo' take a(用户双击鼠标,DEADLOCOP终止了)

是的,的确伟大。并且猜猜DEADLOCOP被部分实现的功能。我说部分地,是因为通过计算机程序来有效地回答检查死锁所牵涉的问题太多了;然而其他的就是既不可决定的又是不能有效计算的了。让我们列举并评论这些理论计算机科学为此目的而衍生的法则:

1.对于一个给定的应用程序(或一系列)的任何状态来说,都能够用来决定系统是否死锁。请回想一个可能出现被死锁的系统。使用所谓的任何给定状态的资源分配图(RAG),它能被用来检查这个状态能够构成死锁。我们稍后将介绍资源分配图。

2.不变量能被计算在本章的后面我们将着眼于计算不变量的技术。这里的问题是计算可能不是很有效。应该被注意的是单线程的不变量不能被计算。这乍听起来有点奇怪,我们认为一个多线程的应用程序是应用程序更难,因为它比但线程的更复杂!我们正在干什么?

重点是多线程中的一个不变量与单线程中的不变量有点不同。后者,我们关心的是变量被看做是内存的状态,例如变量i的值是变量j的两倍,变量p和变量q的值加起来总是7,而多线程中的不变量指的线程的状态,例如如果一个线程1拥有资源2,而另外一个线程一个线程在他们各自的代码段 34。如果我们希望多线程应用程序的不变量也与他们各自的计算状态一体化的信息,例如他们的变量值那问题就变成不可决定的了。

3.一个被标示为死锁的情况是否能够得到被给定的初始状态是可以判定的。然而计算并不是非常有效,它可能要花更长的时间来得到结果,发挥你的聪明才智而不是机械的算法描述出它可能更有效。

从而,尽管DEADLOCOP有可能被写出来,但它并不能非常有效的工作。在某种意义上,着手于一个实现DEADLOCOP的正式框架将更值得,因为不但这样可以最终引导我们通向更先进版的DEADLOCOP,而且它会给我们一个非常清晰的理解,理解我们的多线程应用程序所做的和怎么做的。在下一节,我将带你进入PETRI网络的精彩旅程,希望使你相信为你的应用程序带来些与以前的不同--也就是圆、矩形和箭头的集合。

不管两个线程处在什么状态,我们决定的一些关于应用的语句一直保持真值。因为这个特性

这些语句被叫做不变的(在拉丁语中是“不改变”)。不变式有资格成为计算机科学家最爱玩具的前10位之一,因为你可以使用他们来做许多很酷的事情。在多线程应用程序中,你能够很好的使用检测死锁:当我们讨论GOOFY2的时候所做的是死锁的表现的最基本的描述,然后讨论这样一个死锁将违背一些不变量,因此不会发生。

如果有这样一个程序,我们输入一个应用程序,然后它告诉我们所有的不变量,和程序中存在的死锁不是更好?那样我们就不需要非要去寻找不变量了(同样冒着忘了或误解的这些不变量的风险)并且花费一页页的争论为什么程序能或不能死锁。这样的程序(让我们做下梦,假定它存在,叫做DEADLOCOP)可能是一个多媒体程序并且脱口说出“也,你也许想你是一个好的程序员,但是我告诉你,你给我的程序将比你说的速度更快的崩溃 'Wazoo' take a(用户双击鼠标,DEADLOCOP终止了)

是的,的确伟大。并且猜猜DEADLOCOP被部分实现的功能。我说部分地,是因为通过计算机程序来有效地回答检查死锁所牵涉的问题太多了;然而其他的就是既不可决定的又是不能有效计算的了。让我们列举并评论这些理论计算机科学为此目的而衍生的法则:

1.对于一个给定的应用程序(或一系列)的任何状态来说,都能够用来决定系统是否死锁。请回想一个可能出现被死锁的系统。使用所谓的任何给定状态的资源分配图(RAG),它能被用来检查这个状态能够构成死锁。我们稍后将介绍资源分配图。

2.不变量能被计算在本章的后面我们将着眼于计算不变量的技术。这里的问题是计算可能不是很有效。应该被注意的是单线程的不变量不能被计算。这乍听起来有点奇怪,我们认为一个多线程的应用程序是应用程序更难,因为它比但线程的更复杂!我们正在干什么?

重点是多线程中的一个不变量与单线程中的不变量有点不同。后者,我们关心的是变量被看做是内存的状态,例如变量i的值是变量j的两倍,变量p和变量q的值加起来总是7,而多线程中的不变量指的线程的状态,例如如果一个线程1拥有资源2,而另外一个线程一个线程在他们各自的代码段 34。如果我们希望多线程应用程序的不变量也与他们各自的计算状态一体化的信息,例如他们的变量值那问题就变成不可决定的了。

3.一个被标示为死锁的情况是否能够得到被给定的初始状态是可以判定的。然而计算并不是非常有效,它可能要花更长的时间来得到结果,发挥你的聪明才智而不是机械的算法描述出它可能更有效。

从而,尽管DEADLOCOP有可能被写出来,但它并不能非常有效的工作。在某种意义上,着手于一个实现DEADLOCOP的正式框架将更值得,因为不但这样可以最终引导我们通向更先进版的DEADLOCOP,而且它会给我们一个非常清晰的理解,理解我们的多线程应用程序所做的和怎么做的。在下一节,我将带你进入PETRI网络的精彩旅程,希望使你相信为你的应用程序带来些与以前的不同--也就是圆、矩形和箭头的集合。

你可能感兴趣的:(多线程WIN32程序如何检查死锁(二)-检查死锁的策略)