ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro/SemaphoreSet.pm
Revision: 1.60
Committed: Thu Oct 30 09:57:01 2008 UTC (15 years, 7 months ago) by root
Branch: MAIN
CVS Tags: rel-4_802
Changes since 1.59: +1 -1 lines
Log Message:
4.802

File Contents

# User Rev Content
1 root 1.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 root 1.48 no warnings;
34 root 1.4
35 root 1.1 use Coro ();
36    
37 root 1.60 $VERSION = 4.802;
38 root 1.1
39     =item new [inital count]
40    
41 root 1.36 Creates a new semaphore set with the given initial lock count for each
42 root 1.1 individual semaphore. See L<Coro::Semaphore>.
43    
44     =cut
45    
46     sub new {
47     bless [defined $_[1] ? $_[1] : 1], $_[0];
48     }
49    
50 root 1.31 =item $sem->down ($id)
51 root 1.1
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 root 1.31 =item $status = $sem->timed_down ($id, $timeout)
56 root 1.8
57     Like C<down>, but returns false if semaphore couldn't be acquired within
58     $timeout seconds, otherwise true.
59    
60 root 1.1 =cut
61    
62     sub down {
63 root 1.29 while () {
64     my $sem = ($_[0][1]{$_[1]} ||= [$_[0][0]]);
65 root 1.31
66 root 1.30 if ($sem->[0] > 0) {
67     --$sem->[0];
68 root 1.31 return 1;
69 root 1.30 }
70 root 1.31
71 root 1.1 push @{$sem->[1]}, $Coro::current;
72 root 1.45 &Coro::schedule;
73 root 1.1 }
74 root 1.8 }
75    
76     sub timed_down {
77     require Coro::Timer;
78 root 1.31 my $timeout = Coro::Timer::timeout ($_[2]);
79    
80     while () {
81     my $sem = ($_[0][1]{$_[1]} ||= [$_[0][0]]);
82    
83     if ($sem->[0] > 0) {
84     --$sem->[0];
85     return 1;
86     }
87 root 1.8
88 root 1.10 if ($timeout) {
89 root 1.11 # ugly as hell.
90     for (0..$#{$sem->[1]}) {
91     if ($sem->[1][$_] == $Coro::current) {
92     splice @{$sem->[1]}, $_, 1;
93 root 1.31 return 0;
94 root 1.10 }
95     }
96     die;
97     }
98 root 1.31
99     push @{$sem->[1]}, $Coro::current;
100 root 1.45 &Coro::schedule;
101 root 1.8 }
102 root 1.1 }
103    
104 root 1.31 =item $sem->up ($id)
105 root 1.1
106     Unlock the semaphore again.
107    
108     =cut
109    
110     sub up {
111     my $sem = $_[0][1]{$_[1]};
112 root 1.35
113 root 1.1 if (++$sem->[0] > 0) {
114     (shift @{$sem->[1]})->ready if @{$sem->[1]};
115     }
116 root 1.35
117     delete $_[0][1]{$_[1]} if $sem->[0] == $_[0][0] && !@{$sem->[1] || []};
118 root 1.1 }
119    
120     =item $sem->try
121    
122     Try to C<down> the semaphore. Returns true when this was possible,
123     otherwise return false and leave the semaphore unchanged.
124    
125     =cut
126    
127     sub try {
128     my $sem = ($_[0][1]{$_[1]} ||= [$_[0][0]]);
129     if ($sem->[0] > 0) {
130     --$sem->[0];
131     return 1;
132     } else {
133     return 0;
134     }
135     }
136    
137 root 1.31 =item $sem->waiters ($id)
138 root 1.1
139     In scalar context, returns the number of coroutines waiting for this
140     semaphore.
141    
142     =cut
143    
144     sub waiters {
145 root 1.33 my $sem = $_[0][1]{$_[1]}
146 root 1.32 or return;
147 root 1.33 @{ $_[0][1]{$_[1]}[1] || []}
148 root 1.1 }
149    
150 root 1.31 =item $guard = $sem->guard ($id)
151 root 1.1
152     This method calls C<down> and then creates a guard object. When the guard
153     object is destroyed it automatically calls C<up>.
154    
155 root 1.31 =item $guard = $sem->timed_guard ($id, $timeout)
156 root 1.9
157     Like C<guard>, but returns undef if semaphore couldn't be acquired within
158     $timeout seconds, otherwise the guard object.
159    
160 root 1.1 =cut
161    
162     sub guard {
163     &down;
164 root 1.10 bless [@_], Coro::SemaphoreSet::guard::;
165 root 1.9 }
166    
167 root 1.15 sub timed_guard {
168 root 1.9 &timed_down
169 root 1.10 ? bless [$_[0], $_[1]], Coro::SemaphoreSet::guard::
170 root 1.9 : ();
171 root 1.1 }
172    
173 root 1.9 sub Coro::SemaphoreSet::guard::DESTROY {
174 root 1.1 &up(@{$_[0]});
175     }
176    
177     1;
178    
179     =back
180    
181     =head1 AUTHOR
182    
183 root 1.28 Marc Lehmann <schmorp@schmorp.de>
184 root 1.26 http://home.schmorp.de/
185 root 1.1
186     =cut
187