• No results found

The algorithm and its complications

We designed a parallelUnion-Findbased SCC algorithm based on Proposition 4.3. The result is presented

in Algorithm 17. We explain the algorithm and discuss why the extra methods (Await, WaitDead,

FindDeadlock) are required for maintaining correctness.

In ParSCCp(v), at Line 6 the worker ID is stored inPset(v). We observe from Line 7 that any state from Sp contains p in itsPset. The successors for v are considered in Lines 8-12. We prohibit workers from re-exploringdeadSCCs in Line 9. Proposition 4.3 takes effect in Lines 10 and 11. Here, we apply the notion Invariant 4.3 to check if the cyclevwv has been globally observed (by any worker). If so, we pop and unite states from Sp (in MergePath) until we encounter some statet∈uf[w] :t∈Sp as this is inferred by the invariant. Similar toDijkstra’s algorithm, we keep track of therootfor the SCC. We call

theParSCCprecursively in Line 12. This line is executed for any globallyunseenstate, and any state that is notdead, and has not been visited by workerp, and has not (yet) been observed to be part of a cycle for which some state is part ofSp.

Algorithm 17 A naive parallel SCC algorithm

1: ∀v∈ V:uf[v].status:=unseen 2: ∀i∈[1. . .P] :W aiti:=null 3: Sp:=∅ 4: procedure ParSCCp(v) 5: MakeSet(v) 6: AddWorker(v, p) 7: Sp.push(v) 8: forw∈post(v)do

9: if IsDead(w)then continue 10: if HasWorker(w, p)then 11: MergePathp(w) 12: else ParSCCp(w) 13: if v=Sp.top()then 14: Sp.pop() 15: if Sp=∅then return 16: if IsDead(v)then return

17: else if ¬SameSet(v, Sp.top()) then 18: W ait[p] :=v

19: Awaitp(v)

20: W ait[p] :=null

21: precondition: w∈uf[v] :w∈Sp

22: procedure MergePathp(v)

23: while ¬SameSet(v, Sp.top()) do 24: Union(v, Sp.pop())

25: procedureAwaitp(v)

26: do

27: FindDeadlockp(v) 28: WaitDeadp(v)

29: while¬IsDead(v)∧¬SameSet(v, Sp.top()) 30: procedureWaitDeadp(v)

31: for eachi[0. . .|Sp|]do[takesO(|V|) time] 32: if SameSet(v, Sp[i])then

33: MergePathp(Sp[i])

34: return [SameSet(v, Sp.top())]

35: for eachi[1. . .P]do 36: if HasWorker(v, i)then

37: if W ait[i]6∈uf[v]then return 38: uf[Find(v)].Pset :\={p} [remove worker] 39: while uf[Find(v)].Pset6=∅ ;

40: MarkDead(v)

41: procedureFindDeadlockp(v)

42: deadlock:=SearchCyclep(W ait, v) 43: for eachw∈deadlockdo

44: if HasWorker(w, p)then

45: Union(v, w)

46: MergePathp(w)

Waiting on other workers. When all successors are considered, the algorithm backtracks. We are only interested in possible root candidates for SCCs, hence Line 13. In case the algorithm is executed sequentially, this would be sufficient to mark the SCC asdead. However, due to Line 10, we may have omitted a part of the SCC. Therefore, another worker may still be busy exploring the component. Since it is only possible to discover completed SCCsbottom-up(that is, starting with terminal SCCs), we wait until all other workers have finished exploring this SCC.1 We refer to Figure 4.3 for an example on why this otherwise could go wrong.

In this example, the blue worker has explored the cycle c→d→c (thusuf[c] ={c, d}) and this worker has backtracked toc. We assume that the blue worker halts for the time being. The red worker has explored the patha→b→d. In stated, the red worker ignores successord→c(observe in Line 10, with the notion thatd=Sred.top). Now, the red worker observes no other successors fromdand attempts to backtrack. If we allow this, the red worker backtracks to stateb. Here, the red worker (again) sees no other successors, thus it backtracks again. SincePset(b) ={b}, the red worker notices that it is the only worker inuf[b],

a b c d Pset:{r,b} Pset:{r} Pset:{r,b} b r

Figure 4.3: Example situation for explaining why a wait procedure is applied in Algorithm 17.

hence b gets marked dead. The problem is, that when the blue worker continues and explores the edge

c b, it is unable to detect the cycle c b dc as IsDead(b) holds. Therefore, we state that any worker must wait with backtracking from an SCCCuntil all other workers inPset(C) want to do the same. This waiting procedure is implemented using aW aitarray of sizeP. The table entries denote the states from which each worker wants to backtrack. If we observe for an SCCC that ∀i∈Pset(C) :W ait[i]∈C

(see Lines 35-40 in the algorithm), all workers in Pset(C) are waiting thus every one of these workers may safely backtrack.

Deadlock cycle of waiting workers. By applying the waiting procedure as discussed before, we observe another issue. It may be possible for two (or more) workers to wait on each other, while they backtrack from disjunctufsets. Figure 4.4 exemplifies this problem.

Here, we have on the left picture that the red worker has detected the cyclebcband the blue worker has detected d e d. Thus, uf[b] = {b, c}, Pset(b) = {red}, uf[d] = {d, e}, and Pset(d) = {blue}. Suppose that the blue worker explores d b (and the red worker explores c e) as shown in the right picture. From state b, the blue worker ignores the edgeb c because c uf[Sblue.top]. Thus, the blue worker sets W ait[blue] := b (Line 18) and waits on the red worker. The red worker, however, observes a similar situation and ends up withW ait[red] :=e while waiting for the blue worker. As uf[b]6=uf[e] we have a so-calleddeadlock cycle.

The FindDeadlock procedure (Line 42) is designed to detect such a deadlock cycle. Here, the

SearchCyclepmethod recursively searches over theW aitarray in combination with theirPsets to detect a cycle. In the example it detects that the blue and red worker are waiting on each other. Lines 43-46 unite this cycle. a b c d e Pset:{r,b} Pset:{r} Pset:{b} b r a b c d e Pset:{r,b} Pset:{r,b} Pset:{r,b} b r

Reporting incomplete SCCs. A third problem in the algorithm is observed during the backtrack pro- cedure. With the preventive measures taken from the previous issues, it remains possible for the algorithm to wrongly report partially discovered SCCs as complete ones. This is best explained with the example presented in Figure 4.5. a b c d e f b r Pset: {r,b} a b c d e f Pset:{r,b} b r a b c d e f Pset:{r,b} b r

Figure 4.5: Example that shows how an incomplete SCC can be markeddead.

Here, in the left picture the red worker has first explored the cycle a c e a after which it backtracked and continued exploring the path c db. While the red worker halts for the time being, the blue worker ignores ac(because cuf[Sblue.top=a]) exploresa→b→eas shown in the middle picture. Here, the blue worker correctly unites state b with uf[a] as we have the cycle a b e a. The blue worker backtracks afterwards and waits in stateauntil the red worker has also finished exploring the SCC. In the right picture, the red worker continues from state b and observes the edge b e. Since

e uf[Sred.top =b], this edge is ignored. Now, we face the problem where the red worker has failed to include d in uf[a]. The red worker attempts to backtrack out of uf[a] in which it succeeds since the blue worker is also waiting. As a result, the partial SCC {a, b, c, e} is reported dead. As a side-effect, the red worker now has thedeadstateaon its stack.

Unfortunately, for this problem we did not find an efficient solution. The assumed best approach is to iterate over the complete stack to search if there is agapin the SCC (and merge the states in this gap). This is shown in Lines 31-34. However, this does consists of performing anO(|V|) operation on each backtrack.

Related documents