1b39c5158Smillertpackage Thread::Semaphore; 2b39c5158Smillert 3b39c5158Smillertuse strict; 4b39c5158Smillertuse warnings; 5b39c5158Smillert 6*5759b3d2Safresh1our $VERSION = '2.13'; 7898184e3Ssthen$VERSION = eval $VERSION; 8b39c5158Smillert 9b39c5158Smillertuse threads::shared; 10b39c5158Smillertuse Scalar::Util 1.10 qw(looks_like_number); 11b39c5158Smillert 12898184e3Ssthen# Predeclarations for internal functions 13898184e3Ssthenmy ($validate_arg); 14898184e3Ssthen 15b39c5158Smillert# Create a new semaphore optionally with specified count (count defaults to 1) 16b39c5158Smillertsub new { 17b39c5158Smillert my $class = shift; 18898184e3Ssthen 19898184e3Ssthen my $val :shared = 1; 20898184e3Ssthen if (@_) { 21898184e3Ssthen $val = shift; 22b39c5158Smillert if (! defined($val) || 23b39c5158Smillert ! looks_like_number($val) || 24b39c5158Smillert (int($val) != $val)) 25b39c5158Smillert { 26b39c5158Smillert require Carp; 27b39c5158Smillert $val = 'undef' if (! defined($val)); 28b39c5158Smillert Carp::croak("Semaphore initializer is not an integer: $val"); 29b39c5158Smillert } 30898184e3Ssthen } 31898184e3Ssthen 32b39c5158Smillert return bless(\$val, $class); 33b39c5158Smillert} 34b39c5158Smillert 35b39c5158Smillert# Decrement a semaphore's count (decrement amount defaults to 1) 36b39c5158Smillertsub down { 37b39c5158Smillert my $sema = shift; 38898184e3Ssthen my $dec = @_ ? $validate_arg->(shift) : 1; 39898184e3Ssthen 40b39c5158Smillert lock($$sema); 41b39c5158Smillert cond_wait($$sema) until ($$sema >= $dec); 42b39c5158Smillert $$sema -= $dec; 43b39c5158Smillert} 44b39c5158Smillert 45898184e3Ssthen# Decrement a semaphore's count only if count >= decrement value 46898184e3Ssthen# (decrement amount defaults to 1) 47898184e3Ssthensub down_nb { 48898184e3Ssthen my $sema = shift; 49898184e3Ssthen my $dec = @_ ? $validate_arg->(shift) : 1; 50898184e3Ssthen 51898184e3Ssthen lock($$sema); 52898184e3Ssthen my $ok = ($$sema >= $dec); 53898184e3Ssthen $$sema -= $dec if $ok; 54898184e3Ssthen return $ok; 55898184e3Ssthen} 56898184e3Ssthen 57898184e3Ssthen# Decrement a semaphore's count even if the count goes below 0 58898184e3Ssthen# (decrement amount defaults to 1) 59898184e3Ssthensub down_force { 60898184e3Ssthen my $sema = shift; 61898184e3Ssthen my $dec = @_ ? $validate_arg->(shift) : 1; 62898184e3Ssthen 63898184e3Ssthen lock($$sema); 64898184e3Ssthen $$sema -= $dec; 65898184e3Ssthen} 66898184e3Ssthen 67*5759b3d2Safresh1# Decrement a semaphore's count with timeout 68*5759b3d2Safresh1# (timeout in seconds; decrement amount defaults to 1) 69*5759b3d2Safresh1sub down_timed { 70*5759b3d2Safresh1 my $sema = shift; 71*5759b3d2Safresh1 my $timeout = $validate_arg->(shift); 72*5759b3d2Safresh1 my $dec = @_ ? $validate_arg->(shift) : 1; 73*5759b3d2Safresh1 74*5759b3d2Safresh1 lock($$sema); 75*5759b3d2Safresh1 my $abs = time() + $timeout; 76*5759b3d2Safresh1 until ($$sema >= $dec) { 77*5759b3d2Safresh1 return if !cond_timedwait($$sema, $abs); 78*5759b3d2Safresh1 } 79*5759b3d2Safresh1 $$sema -= $dec; 80*5759b3d2Safresh1 return 1; 81*5759b3d2Safresh1} 82*5759b3d2Safresh1 83b39c5158Smillert# Increment a semaphore's count (increment amount defaults to 1) 84b39c5158Smillertsub up { 85b39c5158Smillert my $sema = shift; 86898184e3Ssthen my $inc = @_ ? $validate_arg->(shift) : 1; 87898184e3Ssthen 88b39c5158Smillert lock($$sema); 89b39c5158Smillert ($$sema += $inc) > 0 and cond_broadcast($$sema); 90b39c5158Smillert} 91b39c5158Smillert 92898184e3Ssthen### Internal Functions ### 93898184e3Ssthen 94898184e3Ssthen# Validate method argument 95898184e3Ssthen$validate_arg = sub { 96898184e3Ssthen my $arg = shift; 97898184e3Ssthen 98898184e3Ssthen if (! defined($arg) || 99898184e3Ssthen ! looks_like_number($arg) || 100898184e3Ssthen (int($arg) != $arg) || 101898184e3Ssthen ($arg < 1)) 102898184e3Ssthen { 103898184e3Ssthen require Carp; 104898184e3Ssthen my ($method) = (caller(1))[3]; 105898184e3Ssthen $method =~ s/Thread::Semaphore:://; 106898184e3Ssthen $arg = 'undef' if (! defined($arg)); 107898184e3Ssthen Carp::croak("Argument to semaphore method '$method' is not a positive integer: $arg"); 108898184e3Ssthen } 109898184e3Ssthen 110898184e3Ssthen return $arg; 111898184e3Ssthen}; 112898184e3Ssthen 113b39c5158Smillert1; 114b39c5158Smillert 115b39c5158Smillert=head1 NAME 116b39c5158Smillert 117b39c5158SmillertThread::Semaphore - Thread-safe semaphores 118b39c5158Smillert 119b39c5158Smillert=head1 VERSION 120b39c5158Smillert 121*5759b3d2Safresh1This document describes Thread::Semaphore version 2.13 122b39c5158Smillert 123b39c5158Smillert=head1 SYNOPSIS 124b39c5158Smillert 125b39c5158Smillert use Thread::Semaphore; 126b39c5158Smillert my $s = Thread::Semaphore->new(); 127b39c5158Smillert $s->down(); # Also known as the semaphore P operation. 128b39c5158Smillert # The guarded section is here 129b39c5158Smillert $s->up(); # Also known as the semaphore V operation. 130b39c5158Smillert 131898184e3Ssthen # Decrement the semaphore only if it would immediately succeed. 132898184e3Ssthen if ($s->down_nb()) { 133898184e3Ssthen # The guarded section is here 134898184e3Ssthen $s->up(); 135898184e3Ssthen } 136898184e3Ssthen 137898184e3Ssthen # Forcefully decrement the semaphore even if its count goes below 0. 138898184e3Ssthen $s->down_force(); 139898184e3Ssthen 140898184e3Ssthen # The default value for semaphore operations is 1 141898184e3Ssthen my $s = Thread::Semaphore->new($initial_value); 142b39c5158Smillert $s->down($down_value); 143b39c5158Smillert $s->up($up_value); 144898184e3Ssthen if ($s->down_nb($down_value)) { 145898184e3Ssthen ... 146898184e3Ssthen $s->up($up_value); 147898184e3Ssthen } 148898184e3Ssthen $s->down_force($down_value); 149b39c5158Smillert 150b39c5158Smillert=head1 DESCRIPTION 151b39c5158Smillert 152b39c5158SmillertSemaphores provide a mechanism to regulate access to resources. Unlike 153b39c5158Smillertlocks, semaphores aren't tied to particular scalars, and so may be used to 154b39c5158Smillertcontrol access to anything you care to use them for. 155b39c5158Smillert 156b39c5158SmillertSemaphores don't limit their values to zero and one, so they can be used to 157b39c5158Smillertcontrol access to some resource that there may be more than one of (e.g., 158b39c5158Smillertfilehandles). Increment and decrement amounts aren't fixed at one either, 159b39c5158Smillertso threads can reserve or return multiple resources at once. 160b39c5158Smillert 161b39c5158Smillert=head1 METHODS 162b39c5158Smillert 163b39c5158Smillert=over 8 164b39c5158Smillert 165b39c5158Smillert=item ->new() 166b39c5158Smillert 167b39c5158Smillert=item ->new(NUMBER) 168b39c5158Smillert 169b39c5158SmillertC<new> creates a new semaphore, and initializes its count to the specified 170b39c5158Smillertnumber (which must be an integer). If no number is specified, the 171b39c5158Smillertsemaphore's count defaults to 1. 172b39c5158Smillert 173b39c5158Smillert=item ->down() 174b39c5158Smillert 175b39c5158Smillert=item ->down(NUMBER) 176b39c5158Smillert 177b39c5158SmillertThe C<down> method decreases the semaphore's count by the specified number 178b39c5158Smillert(which must be an integer >= 1), or by one if no number is specified. 179b39c5158Smillert 180b39c5158SmillertIf the semaphore's count would drop below zero, this method will block 181b39c5158Smillertuntil such time as the semaphore's count is greater than or equal to the 182b39c5158Smillertamount you're C<down>ing the semaphore's count by. 183b39c5158Smillert 184b39c5158SmillertThis is the semaphore "P operation" (the name derives from the Dutch 185b39c5158Smillertword "pak", which means "capture" -- the semaphore operations were 186b39c5158Smillertnamed by the late Dijkstra, who was Dutch). 187b39c5158Smillert 188898184e3Ssthen=item ->down_nb() 189898184e3Ssthen 190898184e3Ssthen=item ->down_nb(NUMBER) 191898184e3Ssthen 192898184e3SsthenThe C<down_nb> method attempts to decrease the semaphore's count by the 193898184e3Ssthenspecified number (which must be an integer >= 1), or by one if no number 194898184e3Ssthenis specified. 195898184e3Ssthen 196898184e3SsthenIf the semaphore's count would drop below zero, this method will return 197898184e3SsthenI<false>, and the semaphore's count remains unchanged. Otherwise, the 198898184e3Ssthensemaphore's count is decremented and this method returns I<true>. 199898184e3Ssthen 200898184e3Ssthen=item ->down_force() 201898184e3Ssthen 202898184e3Ssthen=item ->down_force(NUMBER) 203898184e3Ssthen 204898184e3SsthenThe C<down_force> method decreases the semaphore's count by the specified 205898184e3Ssthennumber (which must be an integer >= 1), or by one if no number is specified. 206898184e3SsthenThis method does not block, and may cause the semaphore's count to drop 207898184e3Ssthenbelow zero. 208898184e3Ssthen 209*5759b3d2Safresh1=item ->down_timed(TIMEOUT) 210*5759b3d2Safresh1 211*5759b3d2Safresh1=item ->down_timed(TIMEOUT, NUMBER) 212*5759b3d2Safresh1 213*5759b3d2Safresh1The C<down_timed> method attempts to decrease the semaphore's count by 1 214*5759b3d2Safresh1or by the specified number within the specified timeout period given in 215*5759b3d2Safresh1seconds (which must be an integer >= 0). 216*5759b3d2Safresh1 217*5759b3d2Safresh1If the semaphore's count would drop below zero, this method will block 218*5759b3d2Safresh1until either the semaphore's count is greater than or equal to the 219*5759b3d2Safresh1amount you're C<down>ing the semaphore's count by, or until the timeout is 220*5759b3d2Safresh1reached. 221*5759b3d2Safresh1 222*5759b3d2Safresh1If the timeout is reached, this method will return I<false>, and the 223*5759b3d2Safresh1semaphore's count remains unchanged. Otherwise, the semaphore's count is 224*5759b3d2Safresh1decremented and this method returns I<true>. 225*5759b3d2Safresh1 226b39c5158Smillert=item ->up() 227b39c5158Smillert 228b39c5158Smillert=item ->up(NUMBER) 229b39c5158Smillert 230b39c5158SmillertThe C<up> method increases the semaphore's count by the number specified 231b39c5158Smillert(which must be an integer >= 1), or by one if no number is specified. 232b39c5158Smillert 233b39c5158SmillertThis will unblock any thread that is blocked trying to C<down> the 234b39c5158Smillertsemaphore if the C<up> raises the semaphore's count above the amount that 235b39c5158Smillertthe C<down> is trying to decrement it by. For example, if three threads 236b39c5158Smillertare blocked trying to C<down> a semaphore by one, and another thread C<up>s 237b39c5158Smillertthe semaphore by two, then two of the blocked threads (which two is 238b39c5158Smillertindeterminate) will become unblocked. 239b39c5158Smillert 240b39c5158SmillertThis is the semaphore "V operation" (the name derives from the Dutch 241b39c5158Smillertword "vrij", which means "release"). 242b39c5158Smillert 243b39c5158Smillert=back 244b39c5158Smillert 245b39c5158Smillert=head1 NOTES 246b39c5158Smillert 247b39c5158SmillertSemaphores created by L<Thread::Semaphore> can be used in both threaded and 248b39c5158Smillertnon-threaded applications. This allows you to write modules and packages 249b39c5158Smillertthat potentially make use of semaphores, and that will function in either 250b39c5158Smillertenvironment. 251b39c5158Smillert 252b39c5158Smillert=head1 SEE ALSO 253b39c5158Smillert 254*5759b3d2Safresh1Thread::Semaphore on MetaCPAN: 255*5759b3d2Safresh1L<https://metacpan.org/release/Thread-Semaphore> 256*5759b3d2Safresh1 257*5759b3d2Safresh1Code repository for CPAN distribution: 258*5759b3d2Safresh1L<https://github.com/Dual-Life/Thread-Semaphore> 259b39c5158Smillert 260b39c5158SmillertL<threads>, L<threads::shared> 261b39c5158Smillert 262*5759b3d2Safresh1Sample code in the I<examples> directory of this distribution on CPAN. 263*5759b3d2Safresh1 264b39c5158Smillert=head1 MAINTAINER 265b39c5158Smillert 266b39c5158SmillertJerry D. Hedden, S<E<lt>jdhedden AT cpan DOT orgE<gt>> 267b39c5158Smillert 268b39c5158Smillert=head1 LICENSE 269b39c5158Smillert 270b39c5158SmillertThis program is free software; you can redistribute it and/or modify it under 271b39c5158Smillertthe same terms as Perl itself. 272b39c5158Smillert 273b39c5158Smillert=cut 274