File Coverage

blib/lib/Thread/Semaphore.pm
Criterion Covered Total %
statement 39 43 90.7
branch 13 18 72.2
condition 5 6 83.3
subroutine 9 10 90.0
pod 5 5 100.0
total 71 82 86.5


line stmt bran cond sub pod time code
1             package Thread::Semaphore;
2              
3 3     3   22370 use strict;
  3         6  
  3         107  
4 3     3   16 use warnings;
  3         6  
  3         226  
5              
6             our $VERSION = '2.12';
7             $VERSION = eval $VERSION;
8              
9 3     3   2903 use threads::shared;
  3         4256  
  3         21  
10 3     3   248 use Scalar::Util 1.10 qw(looks_like_number);
  3         75  
  3         252  
11              
12             # Predeclarations for internal functions
13             my ($validate_arg);
14              
15             # Create a new semaphore optionally with specified count (count defaults to 1)
16             sub new {
17 5     5 1 3382 my $class = shift;
18              
19 3     3   3288 my $val :shared = 1;
  3         4389  
  3         8984  
  5         99  
20 5 100       298 if (@_) {
21 3         7 $val = shift;
22 3 50 100     36 if (! defined($val) ||
      66        
23             ! looks_like_number($val) ||
24             (int($val) != $val))
25             {
26 3         22 require Carp;
27 3 100       10 $val = 'undef' if (! defined($val));
28 3         940 Carp::croak("Semaphore initializer is not an integer: $val");
29             }
30             }
31              
32 2         8 return bless(\$val, $class);
33             }
34              
35             # Decrement a semaphore's count (decrement amount defaults to 1)
36             sub down {
37 7     7 1 5691 my $sema = shift;
38 7 100       28 my $dec = @_ ? $validate_arg->(shift) : 1;
39              
40 2         4 lock($$sema);
41 2         6 cond_wait($$sema) until ($$sema >= $dec);
42 2         6 $$sema -= $dec;
43             }
44              
45             # Decrement a semaphore's count only if count >= decrement value
46             # (decrement amount defaults to 1)
47             sub down_nb {
48 2     2 1 450 my $sema = shift;
49 2 100       8 my $dec = @_ ? $validate_arg->(shift) : 1;
50              
51 2         3 lock($$sema);
52 2         4 my $ok = ($$sema >= $dec);
53 2 100       5 $$sema -= $dec if $ok;
54 2         9 return $ok;
55             }
56              
57             # Decrement a semaphore's count even if the count goes below 0
58             # (decrement amount defaults to 1)
59             sub down_force {
60 0     0 1 0 my $sema = shift;
61 0 0       0 my $dec = @_ ? $validate_arg->(shift) : 1;
62              
63 0         0 lock($$sema);
64 0         0 $$sema -= $dec;
65             }
66              
67             # Increment a semaphore's count (increment amount defaults to 1)
68             sub up {
69 1     1 1 518 my $sema = shift;
70 1 50       7 my $inc = @_ ? $validate_arg->(shift) : 1;
71              
72 1         2 lock($$sema);
73 1 50       35 ($$sema += $inc) > 0 and cond_broadcast($$sema);
74             }
75              
76             ### Internal Functions ###
77              
78             # Validate method argument
79             $validate_arg = sub {
80             my $arg = shift;
81              
82             if (! defined($arg) ||
83             ! looks_like_number($arg) ||
84             (int($arg) != $arg) ||
85             ($arg < 1))
86             {
87             require Carp;
88             my ($method) = (caller(1))[3];
89             $method =~ s/Thread::Semaphore:://;
90             $arg = 'undef' if (! defined($arg));
91             Carp::croak("Argument to semaphore method '$method' is not a positive integer: $arg");
92             }
93              
94             return $arg;
95             };
96              
97             1;
98              
99             =head1 NAME
100              
101             Thread::Semaphore - Thread-safe semaphores
102              
103             =head1 VERSION
104              
105             This document describes Thread::Semaphore version 2.12
106              
107             =head1 SYNOPSIS
108              
109             use Thread::Semaphore;
110             my $s = Thread::Semaphore->new();
111             $s->down(); # Also known as the semaphore P operation.
112             # The guarded section is here
113             $s->up(); # Also known as the semaphore V operation.
114              
115             # Decrement the semaphore only if it would immediately succeed.
116             if ($s->down_nb()) {
117             # The guarded section is here
118             $s->up();
119             }
120              
121             # Forcefully decrement the semaphore even if its count goes below 0.
122             $s->down_force();
123              
124             # The default value for semaphore operations is 1
125             my $s = Thread::Semaphore->new($initial_value);
126             $s->down($down_value);
127             $s->up($up_value);
128             if ($s->down_nb($down_value)) {
129             ...
130             $s->up($up_value);
131             }
132             $s->down_force($down_value);
133              
134             =head1 DESCRIPTION
135              
136             Semaphores provide a mechanism to regulate access to resources. Unlike
137             locks, semaphores aren't tied to particular scalars, and so may be used to
138             control access to anything you care to use them for.
139              
140             Semaphores don't limit their values to zero and one, so they can be used to
141             control access to some resource that there may be more than one of (e.g.,
142             filehandles). Increment and decrement amounts aren't fixed at one either,
143             so threads can reserve or return multiple resources at once.
144              
145             =head1 METHODS
146              
147             =over 8
148              
149             =item ->new()
150              
151             =item ->new(NUMBER)
152              
153             C creates a new semaphore, and initializes its count to the specified
154             number (which must be an integer). If no number is specified, the
155             semaphore's count defaults to 1.
156              
157             =item ->down()
158              
159             =item ->down(NUMBER)
160              
161             The C method decreases the semaphore's count by the specified number
162             (which must be an integer >= 1), or by one if no number is specified.
163              
164             If the semaphore's count would drop below zero, this method will block
165             until such time as the semaphore's count is greater than or equal to the
166             amount you're Cing the semaphore's count by.
167              
168             This is the semaphore "P operation" (the name derives from the Dutch
169             word "pak", which means "capture" -- the semaphore operations were
170             named by the late Dijkstra, who was Dutch).
171              
172             =item ->down_nb()
173              
174             =item ->down_nb(NUMBER)
175              
176             The C method attempts to decrease the semaphore's count by the
177             specified number (which must be an integer >= 1), or by one if no number
178             is specified.
179              
180             If the semaphore's count would drop below zero, this method will return
181             I, and the semaphore's count remains unchanged. Otherwise, the
182             semaphore's count is decremented and this method returns I.
183              
184             =item ->down_force()
185              
186             =item ->down_force(NUMBER)
187              
188             The C method decreases the semaphore's count by the specified
189             number (which must be an integer >= 1), or by one if no number is specified.
190             This method does not block, and may cause the semaphore's count to drop
191             below zero.
192              
193             =item ->up()
194              
195             =item ->up(NUMBER)
196              
197             The C method increases the semaphore's count by the number specified
198             (which must be an integer >= 1), or by one if no number is specified.
199              
200             This will unblock any thread that is blocked trying to C the
201             semaphore if the C raises the semaphore's count above the amount that
202             the C is trying to decrement it by. For example, if three threads
203             are blocked trying to C a semaphore by one, and another thread Cs
204             the semaphore by two, then two of the blocked threads (which two is
205             indeterminate) will become unblocked.
206              
207             This is the semaphore "V operation" (the name derives from the Dutch
208             word "vrij", which means "release").
209              
210             =back
211              
212             =head1 NOTES
213              
214             Semaphores created by L can be used in both threaded and
215             non-threaded applications. This allows you to write modules and packages
216             that potentially make use of semaphores, and that will function in either
217             environment.
218              
219             =head1 SEE ALSO
220              
221             Thread::Semaphore Discussion Forum on CPAN:
222             L
223              
224             L, L
225              
226             =head1 MAINTAINER
227              
228             Jerry D. Hedden, Sjdhedden AT cpan DOT orgE>
229              
230             =head1 LICENSE
231              
232             This program is free software; you can redistribute it and/or modify it under
233             the same terms as Perl itself.
234              
235             =cut