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

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


                 (b)  每当有线程 u 执行操作 acq(u,l)时,假设该操作当前所在的段为 currentSeg,该操作的序号 ID 为
                                                   (k)
                     k,则令ϕ s (currentSeg):=ϕ s (currentSeg)Dl (其中,D表示字符串的拼接函数);
                 (c)  每当有线程 v 执行操作 rel(u,l)时,假设该操作当前所在的段为 currentSeg,该操作的序号 ID 为 k,
                                                  (k)
                     则令ϕ s (currentSeg):=ϕ s (currentSeg)Dl .
             以表 1 中的程序运行轨迹为例,按照上述定义得到的锁增广分段图如图 2 所示.
                                                                                             +
             显然,锁增广分段图中的每个段对应一个线程的若干操作.若图中的两个段 s 1 和 s 2 满足 (, )s s ∈                    SegR (其
                                                                                             σ
                                                                                    1
                                                                                      2
         中, 表示关系的闭包运算),则仅当 s 1 中的操作全部执行完毕后方能执行 s 2 中的操作,记此种关系为 s 1  s 2 .
            +
             图 2 中,2 6 与 5 6 成立,意味着仅当 2 号段与 5 号段中操作执行完毕后方能执行 6 号段中的操作;6 7 与
         7 6 均不成立,这意味着,6 号段与 7 号段之间的操作不存在执行次序上的先后依赖关系,此时认为这两组操作可
         以并发.
         2.3   时序增广锁图
             本节在扩展锁图的基础上添加语句的执行时序信息,以区分循环中不同轮次的锁获取操作;同时,在图中标
         注每个操作在运行轨迹中的操作序号 ID(据此定位操作在分段图中的位置),由此提出时序增广锁图的概念.
             以表 2 中的程序运行轨迹为例,拟构造的时序增广锁图如图 3 所示.其中,2 号弧的标记信息由扩展锁图图
                                                            (5)
         1(b)中的〈5,(threadA,{G,o1}),5〉扩充为了〈5,(threadA,{G,o1}),1,5〉 ,扩充图中的数字 1 表示本次操作是线程
         threadA 第 1 次申请锁 o2,标记右上角数字 5 为该弧所对应操作在执行轨迹上的操作序号 ID.5 号弧的标记信息
         变为了〈7,(threadA,{G,o1}),2,7〉 (11) .在扩展锁图中标记相同、无法区分的 2 号弧和 5 号弧,在图 3 的时序增广锁
         图中有了不同的标记.

                 1:〈2,(threadA,{G}),1,5〉 (4)  3:〈2,(threadA,{G,o1}),1,5〉 (5)
                                                             8:〈6,(threadB,{m}),1,6〉 (22)
                                  G
                                                          n                      m
                                                              12:〈4,(threadC,{n}),1,4〉 (33)
                                 6:〈7,(threadA,{G,o1}),2,7〉  (11)  13:〈4,(threadC,{n}),1,4〉 (35)
                   4:〈7,(threadA,{G}),2,7〉 (10)                 10:〈6,(threadB,{m,q}),1,6〉 (25)

                                                            p             9:〈6,(threadB,{n}),1,6〉 (24)
                                          (5)
                  o1      2:〈5,(threadA,{G,o1}),1,5〉  o2
                                                                15:〈4,(threadC,{n,p}),1,4〉 (36)
                           5:〈7,(threadA,{G,o1}),2,7〉 (11)
                                                            11:〈6,(threadB,{m,q}),1,6〉  (25)
                                                                                q
                            7:〈6,(threadB,{o2}),1,6〉 (18)
                                                            14:〈4,(threadC,{n,p}),1,4〉 (36)
                      Fig.3  Time-augmented lock graph corresponding to the running trace in Table 2
                                    图 3   表 2 运行轨迹对应的时序增广锁图

             经上述处理后,一方面可以保证同一个锁授权语句在循环中的多次执行能区分开来;另一方面,可根据各条
         弧所对应操作在运行轨迹中的序号 ID 确定其在锁增广分段图中的位置,从而为后续死锁检测提供方便.下面给
         出时序增广锁图的形式化定义与构造规则.
             定义 4(时序增广锁图).  给定一个多线程程序的运行轨迹σ=e 1 e 2 e 3 ...e n ,其对应的时序增广锁图 LockG_
         Order σ 是满足如下条件的二元组(V σ ,R σ ).
             (1)  V σ 为顶点集,每个顶点对应σ中出现的一个锁对象;
             (2)  R σ ⊆V σ ×Γ×V σ 为关系集,Γ是图中各关系所对应之有向弧的标签集合;
             (3)  每当σ中有一个线程 t 在持有锁 lock 1 的前提下获取锁 lock 2 时,假设该操作的序号 ID 为 k,则为此操作
   112   113   114   115   116   117   118   119   120   121   122