Page 121 - 《软件学报》2021年第6期
P. 121

鲁法明  等:基于锁增广分段图的多线程程序死锁检测                                                        1695


             30.              IF (DependG_Lock c 不存在有向环)
             31.                将 c 加入集合 DeadlockCycles(LockG_Order σ );   //得到一个潜在死锁
             32.              }  //IF
             33.          }   //IF
             34.       }   //IF
             35.    }   //IF
             36. }    //FOR EACH
             37. RETURN DeadlockCycles(LockG_Order σ ).
             相比传统方法基于分段图和扩展锁图进行的死锁检测,算法 1 的规则(3)基于锁增广分段图进行的段间因
         果依赖的判定更加准确,第 5 条规则能排除“历史持有锁-持有锁”耦合因果依赖关系导致的误报.如此一来,对于
         图 3 中 4 组有向弧对{2,7},{5,7},{8,12},{11,15}构成的有向环路,算法 1 能准确地识别出其中{5,7}和{8,12}对应
         的环路会导致死锁,而{2,7}和{11,15}对应的环路不会导致死锁,从而避免了它们给传统方法带来的死锁误报.

         4    相关工作对比与实验评估

         4.1   相关工作对比

             基于锁图、环锁依赖链、分段图与分段锁图以及本文方法对表 2 中的程序运行轨迹进行分析,所得死锁检
         测结果见表 3.除本文方法之外,其余 3 类方法会将锁图中的每条环路都认定为一个死锁.第 1 行对应的死锁误
         报,是因为它们无法识别“锁-start”耦合因果依赖关系;第 4 行对应的死锁误报,是因为它们未处理“历史持有锁-
         持有锁”耦合因果依赖关系.而实际上,这两类关系都可能导致环路中的某些操作无法并发.本文方法通过对传
         统锁图和分段图的改进弥补了上述不足,并借助锁增广分段图和“历史持有锁-持有锁”耦合因果关系图对上述
         情形进行了识别,从而能避免了传统方法中存在的上述死锁误报现象.
             Table 3    Deadlock detection results of different methods towards dynamic analysis of the trace in Table 1
                          表 3   不同方法对表 1 运行轨迹进行动态分析所得之死锁检测结果
                                                                是否       不同模型的死锁检测结果
                  锁对象的循环等待
                  (对应潜在死锁状态)           时序增广锁图中对应的操作与弧           真实   锁图    环锁    分段图与     本文
                                                                死锁        依赖链    分段锁图     方法
              threadA 第 1 次执行第 14 行代码  acq(o2)@2:〈5,(threadA,{G,o1}),1,5〉 (5)  否   是   是   是   否
                threadB 执行第 22 行代码    acq(o1)@7:〈6,(threadB,{o2}),1,6〉 (18)
              threadA 第 2 次执行第 14 行代码  acq(o2)@5:〈7,(threadA,{G,o1}),2,7〉  (11)  是   是   是   是   是
                threadB 执行第 22 行代码     acq(o1)@7:〈6,(threadB,{o2}),1,6〉  (18)
                threadB 执行第 25 行代码     acq(n)@8:〈6,(threadB,{m}),1,6〉 (22)
                threadC 执行第 33 行代码    acq(m)@12:〈4,(threadC,{n}),1,4〉 (33)    是   是   是   是   是
                threadB 执行第 27 行代码    acq(p)@11:〈6,(threadB,{m,q}),1,6〉 (25)
                threadC 执行第 35 行代码    acq(q)@15:〈4,(threadC,{n,p}),1,4〉 (36)  否   是   是   是   否

             需要进一步指出的是:动态分析方法从程序运行轨迹中捕获的程序行为信息始终有限,丢失的信息既可能
         导致检测出的潜在死锁不是真实死锁,还可能导致原本不存在死锁的程序被误定为存在死锁.针对这种情况,在
         死锁分析领域,除上述提到的死锁检测方法外,有学者开始研究潜在死锁的重演.所谓死锁重演,就是针对检测
         到的潜在死锁,通过对程序执行的主动干预和调度,使潜在死锁在为真实死锁的情况下会被尽可能地触发,重演
         成功的潜在死锁必是真实死锁.例如,对本文提出的“历史持有锁-持有锁”耦合因果依赖导致的死锁误报,文献
         [21]中曾有一个程序实例.但文献[21]中采用的死锁检测算法 ConLock+并不能排除该误报,文中是通过死锁重
         演来排除这一误报的.相比而言,本文提出的死锁检测算法无需重演,在检测阶段即可将该误报排除.不过,即便
         如此,由于程序轨迹中不可避免地会丢失一些程序行为信息,即使本文方法也存在某些类似的误报现象,所以死
         锁的重演也是本文后续研究的重点方向之一.
             在死锁重演方面,文献[20,22]首次提出一种面向缺陷重演的随机调度方法,通过不同调度方案下程序的大
   116   117   118   119   120   121   122   123   124   125   126