ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro/SemaphoreSet.pm
Revision: 1.9
Committed: Tue Nov 27 03:11:48 2001 UTC (22 years, 6 months ago) by root
Branch: MAIN
Changes since 1.8: +13 -4 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 =head1 NAME
2
3 Coro::SemaphoreSet - hash of semaphores.
4
5 =head1 SYNOPSIS
6
7 use Coro::SemaphoreSet;
8
9 $sig = new Coro::SemaphoreSet [initial value];
10
11 $sig->down("semaphoreid"); # wait for signal
12
13 # ... some other "thread"
14
15 $sig->up("semaphoreid");
16
17 =head1 DESCRIPTION
18
19 This module implements sets of counting semaphores (see
20 L<Coro::Semaphore>). It is nothing more than a hash with normal semaphores
21 as members, but is more efficiently managed.
22
23 This is useful if you want to allow parallel tasks to run in parallel but
24 not on the same problem. Just use a SemaphoreSet and lock on the problem
25 identifier.
26
27 =over 4
28
29 =cut
30
31 package Coro::SemaphoreSet;
32
33 no warnings qw(uninitialized);
34
35 use Coro ();
36
37 $VERSION = 0.52;
38
39 =item new [inital count]
40
41 Creates a new sempahore set with the given initial lock count for each
42 individual semaphore. See L<Coro::Semaphore>.
43
44 =cut
45
46 sub new {
47 bless [defined $_[1] ? $_[1] : 1], $_[0];
48 }
49
50 =item $sem->down($id)
51
52 Decrement the counter, therefore "locking" the named semaphore. This
53 method waits until the semaphore is available if the counter is zero.
54
55 =item $status = $sem->timed_down($id, $timeout)
56
57 Like C<down>, but returns false if semaphore couldn't be acquired within
58 $timeout seconds, otherwise true.
59
60 =cut
61
62 sub down {
63 my $sem = ($_[0][1]{$_[1]} ||= [$_[0][0]]);
64 while ($sem->[0] <= 0) {
65 push @{$sem->[1]}, $Coro::current;
66 Coro::schedule;
67 }
68 --$sem->[0];
69 }
70
71 sub timed_down {
72 require Coro::Timer;
73 my $timeout = Coro::Timer::timeout($_[2]);
74
75 my $sem = ($_[0][1]{$_[1]} ||= [$_[0][0]]);
76 while ($sem->[0] <= 0) {
77 push @{$sem->[1]}, $Coro::current;
78 Coro::schedule;
79 $timeout and return;
80 }
81 --$sem->[0];
82 return 1;
83 }
84
85 =item $sem->up($id)
86
87 Unlock the semaphore again.
88
89 =cut
90
91 sub up {
92 my $sem = $_[0][1]{$_[1]};
93 if (++$sem->[0] > 0) {
94 (shift @{$sem->[1]})->ready if @{$sem->[1]};
95 }
96 delete $_[0][1]{$_[1]} if $sem->[0] == $_[0][0];
97 }
98
99 =item $sem->try
100
101 Try to C<down> the semaphore. Returns true when this was possible,
102 otherwise return false and leave the semaphore unchanged.
103
104 =cut
105
106 sub try {
107 my $sem = ($_[0][1]{$_[1]} ||= [$_[0][0]]);
108 if ($sem->[0] > 0) {
109 --$sem->[0];
110 return 1;
111 } else {
112 return 0;
113 }
114 }
115
116 =item $sem->waiters($id)
117
118 In scalar context, returns the number of coroutines waiting for this
119 semaphore.
120
121 =cut
122
123 sub waiters {
124 @{$_[0][1]{$_[1]}};
125 }
126
127 =item $guard = $sem->guard($id)
128
129 This method calls C<down> and then creates a guard object. When the guard
130 object is destroyed it automatically calls C<up>.
131
132 =item $guard = $sem->timed_guard($id, $timeout)
133
134 Like C<guard>, but returns undef if semaphore couldn't be acquired within
135 $timeout seconds, otherwise the guard object.
136
137 =cut
138
139 sub guard {
140 &down;
141 bless [@_], Coro::SemaphoreSet::guard;
142 }
143
144 sub guard {
145 &timed_down
146 ? bless [$_[0], $_[1]], Coro::SemaphoreSet::guard
147 : ();
148 }
149
150 sub Coro::SemaphoreSet::guard::DESTROY {
151 &up(@{$_[0]});
152 }
153
154 1;
155
156 =back
157
158 =head1 AUTHOR
159
160 Marc Lehmann <pcg@goof.com>
161 http://www.goof.com/pcg/marc/
162
163 =cut
164