ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro/SemaphoreSet.pm
Revision: 1.105
Committed: Wed Aug 3 09:43:04 2011 UTC (12 years, 10 months ago) by root
Branch: MAIN
CVS Tags: rel-6_03
Changes since 1.104: +1 -1 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 =head1 NAME
2    
3 root 1.70 Coro::SemaphoreSet - efficient set of counting semaphores
4 root 1.1
5     =head1 SYNOPSIS
6    
7 root 1.97 use Coro;
8 root 1.1
9     $sig = new Coro::SemaphoreSet [initial value];
10    
11 root 1.73 $sig->down ("semaphoreid"); # wait for signal
12 root 1.1
13     # ... some other "thread"
14    
15 root 1.73 $sig->up ("semaphoreid");
16 root 1.1
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 root 1.96 You don't have to load C<Coro::SemaphoreSet> manually, it will be loaded
28     automatically when you C<use Coro> and call the C<new> constructor.
29    
30 root 1.1 =over 4
31    
32     =cut
33    
34     package Coro::SemaphoreSet;
35    
36 root 1.89 use common::sense;
37 root 1.4
38 root 1.105 our $VERSION = 6.03;
39 root 1.1
40 root 1.68 use Coro::Semaphore ();
41 root 1.1
42     =item new [inital count]
43    
44 root 1.36 Creates a new semaphore set with the given initial lock count for each
45 root 1.1 individual semaphore. See L<Coro::Semaphore>.
46    
47     =cut
48    
49     sub new {
50 root 1.74 bless [defined $_[1] ? $_[1] : 1], $_[0]
51 root 1.1 }
52    
53 root 1.68 =item $semset->down ($id)
54 root 1.1
55     Decrement the counter, therefore "locking" the named semaphore. This
56     method waits until the semaphore is available if the counter is zero.
57    
58     =cut
59    
60     sub down {
61 root 1.77 # Coro::Semaphore::down increases the refcount, which we check in _may_delete
62 root 1.76 Coro::Semaphore::down ($_[0][1]{$_[1]} ||= Coro::Semaphore::_alloc $_[0][0]);
63 root 1.1 }
64    
65 root 1.68 #ub timed_down {
66     # require Coro::Timer;
67     # my $timeout = Coro::Timer::timeout ($_[2]);
68     #
69     # while () {
70     # my $sem = ($_[0][1]{$_[1]} ||= [$_[0][0]]);
71     #
72     # if ($sem->[0] > 0) {
73     # --$sem->[0];
74     # return 1;
75     # }
76     #
77     # if ($timeout) {
78     # # ugly as hell.
79     # for (0..$#{$sem->[1]}) {
80     # if ($sem->[1][$_] == $Coro::current) {
81     # splice @{$sem->[1]}, $_, 1;
82     # return 0;
83     # }
84     # }
85     # die;
86     # }
87     #
88     # push @{$sem->[1]}, $Coro::current;
89     # &Coro::schedule;
90     # }
91     #
92    
93     =item $semset->up ($id)
94    
95 root 1.77 Unlock the semaphore again. If the semaphore reaches the default count for
96     this set and has no waiters, the space allocated for it will be freed.
97 root 1.1
98     =cut
99    
100     sub up {
101 root 1.68 my ($self, $id) = @_;
102    
103 root 1.75 my $sem = $self->[1]{$id} ||= Coro::Semaphore::_alloc $self->[0];
104 root 1.68
105 root 1.75 Coro::Semaphore::up $sem;
106 root 1.68
107 root 1.75 delete $self->[1]{$id}
108 root 1.77 if _may_delete $sem, $self->[0], 1;
109 root 1.1 }
110    
111 root 1.73 =item $semset->try ($id)
112 root 1.1
113     Try to C<down> the semaphore. Returns true when this was possible,
114     otherwise return false and leave the semaphore unchanged.
115    
116     =cut
117    
118     sub try {
119 root 1.75 Coro::Semaphore::try ($_[0][1]{$_[1]} || return $_[0][0] > 0)
120 root 1.73 }
121    
122     =item $semset->count ($id)
123    
124     Return the current semaphore count for the specified semaphore.
125    
126     =cut
127    
128     sub count {
129 root 1.75 Coro::Semaphore::count ($_[0][1]{$_[1]} || return $_[0][0]);
130     }
131    
132     =item $semset->waiters ($id)
133    
134     Returns the number (in scalar context) or list (in list context) of
135     waiters waiting on the specified semaphore.
136    
137     =cut
138    
139     sub waiters {
140     Coro::Semaphore::waiters ($_[0][1]{$_[1]} || return);
141 root 1.73 }
142    
143     =item $semset->wait ($id)
144    
145     Same as Coro::Semaphore::wait on the specified semaphore.
146    
147     =cut
148    
149     sub wait {
150 root 1.86 Coro::Semaphore::wait ($_[0][1]{$_[1]} || return);
151 root 1.1 }
152    
153 root 1.68 =item $guard = $semset->guard ($id)
154 root 1.1
155     This method calls C<down> and then creates a guard object. When the guard
156     object is destroyed it automatically calls C<up>.
157    
158     =cut
159    
160     sub guard {
161     &down;
162 root 1.79 bless [@_], Coro::SemaphoreSet::guard::
163 root 1.9 }
164    
165 root 1.68 #ub timed_guard {
166     # &timed_down
167     # ? bless [$_[0], $_[1]], Coro::SemaphoreSet::guard::
168     # : ();
169     #
170    
171     sub Coro::SemaphoreSet::guard::DESTROY {
172     up @{$_[0]};
173 root 1.1 }
174    
175 root 1.68 =item $semaphore = $semset->sem ($id)
176    
177     This SemaphoreSet version is based on Coro::Semaphore's. This function
178     creates (if necessary) the underlying Coro::Semaphore object and returns
179     it. You may legally call any Coro::Semaphore method on it, but note that
180     calling C<< $semset->up >> can invalidate the returned semaphore.
181    
182     =cut
183    
184     sub sem {
185 root 1.75 bless +($_[0][1]{$_[1]} ||= Coro::Semaphore::_alloc $_[0][0]),
186     Coro::Semaphore::;
187 root 1.1 }
188    
189     1;
190    
191     =back
192    
193     =head1 AUTHOR
194    
195 root 1.28 Marc Lehmann <schmorp@schmorp.de>
196 root 1.26 http://home.schmorp.de/
197 root 1.1
198     =cut
199