ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro/SemaphoreSet.pm
Revision: 1.24
Committed: Fri May 14 13:25:09 2004 UTC (20 years ago) by pcg
Branch: MAIN
Changes since 1.23: +1 -1 lines
Log Message:
*** empty log message ***

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 pcg 1.20 BEGIN { eval { require warnings } && warnings->unimport ("uninitialized") }
34 root 1.4
35 root 1.1 use Coro ();
36    
37 pcg 1.24 $VERSION = 0.97;
38 root 1.1
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 root 1.8 =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 root 1.1 =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 root 1.8 }
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 root 1.10 if ($timeout) {
80 root 1.11 # ugly as hell.
81     for (0..$#{$sem->[1]}) {
82     if ($sem->[1][$_] == $Coro::current) {
83     splice @{$sem->[1]}, $_, 1;
84 root 1.10 return;
85     }
86     }
87     die;
88     }
89 root 1.8 }
90     --$sem->[0];
91     return 1;
92 root 1.1 }
93    
94     =item $sem->up($id)
95    
96     Unlock the semaphore again.
97    
98     =cut
99    
100     sub up {
101     my $sem = $_[0][1]{$_[1]};
102     if (++$sem->[0] > 0) {
103     (shift @{$sem->[1]})->ready if @{$sem->[1]};
104     }
105     delete $_[0][1]{$_[1]} if $sem->[0] == $_[0][0];
106     }
107    
108     =item $sem->try
109    
110     Try to C<down> the semaphore. Returns true when this was possible,
111     otherwise return false and leave the semaphore unchanged.
112    
113     =cut
114    
115     sub try {
116     my $sem = ($_[0][1]{$_[1]} ||= [$_[0][0]]);
117     if ($sem->[0] > 0) {
118     --$sem->[0];
119     return 1;
120     } else {
121     return 0;
122     }
123     }
124    
125     =item $sem->waiters($id)
126    
127     In scalar context, returns the number of coroutines waiting for this
128     semaphore.
129    
130     =cut
131    
132     sub waiters {
133     @{$_[0][1]{$_[1]}};
134     }
135    
136     =item $guard = $sem->guard($id)
137    
138     This method calls C<down> and then creates a guard object. When the guard
139     object is destroyed it automatically calls C<up>.
140    
141 root 1.9 =item $guard = $sem->timed_guard($id, $timeout)
142    
143     Like C<guard>, but returns undef if semaphore couldn't be acquired within
144     $timeout seconds, otherwise the guard object.
145    
146 root 1.1 =cut
147    
148     sub guard {
149     &down;
150 root 1.10 bless [@_], Coro::SemaphoreSet::guard::;
151 root 1.9 }
152    
153 root 1.15 sub timed_guard {
154 root 1.9 &timed_down
155 root 1.10 ? bless [$_[0], $_[1]], Coro::SemaphoreSet::guard::
156 root 1.9 : ();
157 root 1.1 }
158    
159 root 1.9 sub Coro::SemaphoreSet::guard::DESTROY {
160 root 1.1 &up(@{$_[0]});
161     }
162    
163     1;
164    
165     =back
166    
167     =head1 AUTHOR
168    
169     Marc Lehmann <pcg@goof.com>
170     http://www.goof.com/pcg/marc/
171    
172     =cut
173