1package Thread::Semaphore; 2 3use strict; 4use warnings; 5 6our $VERSION = '2.12'; 7$VERSION = eval $VERSION; 8 9use threads::shared; 10use Scalar::Util 1.10 qw(looks_like_number); 11 12# Predeclarations for internal functions 13my ($validate_arg); 14 15# Create a new semaphore optionally with specified count (count defaults to 1) 16sub new { 17 my $class = shift; 18 19 my $val :shared = 1; 20 if (@_) { 21 $val = shift; 22 if (! defined($val) || 23 ! looks_like_number($val) || 24 (int($val) != $val)) 25 { 26 require Carp; 27 $val = 'undef' if (! defined($val)); 28 Carp::croak("Semaphore initializer is not an integer: $val"); 29 } 30 } 31 32 return bless(\$val, $class); 33} 34 35# Decrement a semaphore's count (decrement amount defaults to 1) 36sub down { 37 my $sema = shift; 38 my $dec = @_ ? $validate_arg->(shift) : 1; 39 40 lock($$sema); 41 cond_wait($$sema) until ($$sema >= $dec); 42 $$sema -= $dec; 43} 44 45# Decrement a semaphore's count only if count >= decrement value 46# (decrement amount defaults to 1) 47sub down_nb { 48 my $sema = shift; 49 my $dec = @_ ? $validate_arg->(shift) : 1; 50 51 lock($$sema); 52 my $ok = ($$sema >= $dec); 53 $$sema -= $dec if $ok; 54 return $ok; 55} 56 57# Decrement a semaphore's count even if the count goes below 0 58# (decrement amount defaults to 1) 59sub down_force { 60 my $sema = shift; 61 my $dec = @_ ? $validate_arg->(shift) : 1; 62 63 lock($$sema); 64 $$sema -= $dec; 65} 66 67# Increment a semaphore's count (increment amount defaults to 1) 68sub up { 69 my $sema = shift; 70 my $inc = @_ ? $validate_arg->(shift) : 1; 71 72 lock($$sema); 73 ($$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 971; 98 99=head1 NAME 100 101Thread::Semaphore - Thread-safe semaphores 102 103=head1 VERSION 104 105This 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 136Semaphores provide a mechanism to regulate access to resources. Unlike 137locks, semaphores aren't tied to particular scalars, and so may be used to 138control access to anything you care to use them for. 139 140Semaphores don't limit their values to zero and one, so they can be used to 141control access to some resource that there may be more than one of (e.g., 142filehandles). Increment and decrement amounts aren't fixed at one either, 143so 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 153C<new> creates a new semaphore, and initializes its count to the specified 154number (which must be an integer). If no number is specified, the 155semaphore's count defaults to 1. 156 157=item ->down() 158 159=item ->down(NUMBER) 160 161The C<down> 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 164If the semaphore's count would drop below zero, this method will block 165until such time as the semaphore's count is greater than or equal to the 166amount you're C<down>ing the semaphore's count by. 167 168This is the semaphore "P operation" (the name derives from the Dutch 169word "pak", which means "capture" -- the semaphore operations were 170named by the late Dijkstra, who was Dutch). 171 172=item ->down_nb() 173 174=item ->down_nb(NUMBER) 175 176The C<down_nb> method attempts to decrease the semaphore's count by the 177specified number (which must be an integer >= 1), or by one if no number 178is specified. 179 180If the semaphore's count would drop below zero, this method will return 181I<false>, and the semaphore's count remains unchanged. Otherwise, the 182semaphore's count is decremented and this method returns I<true>. 183 184=item ->down_force() 185 186=item ->down_force(NUMBER) 187 188The C<down_force> method decreases the semaphore's count by the specified 189number (which must be an integer >= 1), or by one if no number is specified. 190This method does not block, and may cause the semaphore's count to drop 191below zero. 192 193=item ->up() 194 195=item ->up(NUMBER) 196 197The C<up> 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 200This will unblock any thread that is blocked trying to C<down> the 201semaphore if the C<up> raises the semaphore's count above the amount that 202the C<down> is trying to decrement it by. For example, if three threads 203are blocked trying to C<down> a semaphore by one, and another thread C<up>s 204the semaphore by two, then two of the blocked threads (which two is 205indeterminate) will become unblocked. 206 207This is the semaphore "V operation" (the name derives from the Dutch 208word "vrij", which means "release"). 209 210=back 211 212=head1 NOTES 213 214Semaphores created by L<Thread::Semaphore> can be used in both threaded and 215non-threaded applications. This allows you to write modules and packages 216that potentially make use of semaphores, and that will function in either 217environment. 218 219=head1 SEE ALSO 220 221Thread::Semaphore Discussion Forum on CPAN: 222L<http://www.cpanforum.com/dist/Thread-Semaphore> 223 224L<threads>, L<threads::shared> 225 226=head1 MAINTAINER 227 228Jerry D. Hedden, S<E<lt>jdhedden AT cpan DOT orgE<gt>> 229 230=head1 LICENSE 231 232This program is free software; you can redistribute it and/or modify it under 233the same terms as Perl itself. 234 235=cut 236