From: Dave Mitchell Date: Wed, 22 May 2002 12:53:21 +0000 (+0100) Subject: Re: where threads cond.t hangs X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=07e9638fb63f29c49a4db9693ee116a8ab4232a2;p=p5sagit%2Fp5-mst-13.2.git Re: where threads cond.t hangs Message-ID: <20020522125320.E12794@fdgroup.com> p4raw-id: //depot/perl@16734 --- diff --git a/ext/threads/shared/t/cond.t b/ext/threads/shared/t/cond.t index aa80aab..8c482cc 100644 --- a/ext/threads/shared/t/cond.t +++ b/ext/threads/shared/t/cond.t @@ -10,7 +10,7 @@ BEGIN { } } $|++; -print "1..29\n"; +print "1..31\n"; use strict; @@ -191,59 +191,67 @@ sub ok { { my $counter : shared = 0; - sub waiter { - lock($counter); - $counter++; - cond_wait($counter); - $counter += 10; - } - - my $tr1 = threads->new(\&waiter); - my $tr2 = threads->new(\&waiter); - my $tr3 = threads->new(\&waiter); + # broad(N) forks off broad(N-1) and goes into a wait, in such a way + # that it's guaranteed to reach the wait before its child enters the + # locked region. When N reaches 0, the child instead does a + # cond_broadcast to wake all its ancestors. - while (1) { - lock $counter; - # make sure all 3 threads are waiting - next unless $counter == 3; - cond_broadcast $counter; - last; + sub broad { + my $n = shift; + my $th; + { + lock($counter); + if ($n > 0) { + $counter++; + $th = threads->new(\&broad, $n-1); + cond_wait($counter); + $counter += 10; + } + else { + ok(1, $counter == 3, "cond_broadcast: all three waiting"); + cond_broadcast($counter); + } + } + $th->join if $th; } - $tr1->join(); $tr2->join(); $tr3->join(); - ok(1, $counter == 33, "cond_broadcast: all three threads woken"); + + threads->new(\&broad, 3)->join; + ok(2, $counter == 33, "cond_broadcast: all three threads woken"); print "# counter=$counter\n"; - $Base += 1; + $Base += 2; - # ditto with refs and shared() + + # ditto, but with refs and shared() my $counter2 = 0; share($counter2); my $r = \$counter2; - sub waiter2 { - lock($r); - $$r++; - cond_wait($r); - $$r += 10; + sub broad2 { + my $n = shift; + my $th; + { + lock($r); + if ($n > 0) { + $$r++; + $th = threads->new(\&broad2, $n-1); + cond_wait($r); + $$r += 10; + } + else { + ok(1, $$r == 3, "cond_broadcast: ref: all three waiting"); + cond_broadcast($r); + } + } + $th->join if $th; } - $tr1 = threads->new(\&waiter2); - $tr2 = threads->new(\&waiter2); - $tr3 = threads->new(\&waiter2); - - while (1) { - lock($r); - # make sure all 3 threads are waiting - next unless $$r == 3; - cond_broadcast $r; - last; - } - $tr1->join(); $tr2->join(); $tr3->join(); - ok(1, $$r == 33, "cond_broadcast: ref: all three threads woken"); + threads->new(\&broad2, 3)->join;; + ok(2, $$r == 33, "cond_broadcast: ref: all three threads woken"); print "# counter=$$r\n"; - $Base += 1; + $Base += 2; }