ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro/SemaphoreSet.pm
Revision: 1.5
Committed: Mon Sep 24 01:36:20 2001 UTC (22 years, 9 months ago) by root
Branch: MAIN
Changes since 1.4: +1 -1 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.5;
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 =cut
56
57 sub down {
58 my $sem = ($_[0][1]{$_[1]} ||= [$_[0][0]]);
59 while ($sem->[0] <= 0) {
60 push @{$sem->[1]}, $Coro::current;
61 Coro::schedule;
62 }
63 --$sem->[0];
64 }
65
66 =item $sem->up($id)
67
68 Unlock the semaphore again.
69
70 =cut
71
72 sub up {
73 my $sem = $_[0][1]{$_[1]};
74 if (++$sem->[0] > 0) {
75 (shift @{$sem->[1]})->ready if @{$sem->[1]};
76 }
77 delete $_[0][1]{$_[1]} if $sem->[0] == $_[0][0];
78 }
79
80 =item $sem->try
81
82 Try to C<down> the semaphore. Returns true when this was possible,
83 otherwise return false and leave the semaphore unchanged.
84
85 =cut
86
87 sub try {
88 my $sem = ($_[0][1]{$_[1]} ||= [$_[0][0]]);
89 if ($sem->[0] > 0) {
90 --$sem->[0];
91 return 1;
92 } else {
93 return 0;
94 }
95 }
96
97 =item $sem->waiters($id)
98
99 In scalar context, returns the number of coroutines waiting for this
100 semaphore.
101
102 =cut
103
104 sub waiters {
105 @{$_[0][1]{$_[1]}};
106 }
107
108 =item $guard = $sem->guard($id)
109
110 This method calls C<down> and then creates a guard object. When the guard
111 object is destroyed it automatically calls C<up>.
112
113 =cut
114
115 sub guard {
116 &down;
117 # double indirection because bless works on the referenced
118 # object, not (only) on the reference itself.
119 bless [@_], Coro::SemaphoreSet::Guard::;
120 }
121
122 sub Coro::SemaphoreSet::Guard::DESTROY {
123 &up(@{$_[0]});
124 }
125
126 1;
127
128 =back
129
130 =head1 AUTHOR
131
132 Marc Lehmann <pcg@goof.com>
133 http://www.goof.com/pcg/marc/
134
135 =cut
136