Purl Gurl said:
Works great for a Control Z signal.
Use of Control C creates a kernel 32 fatal exception.
I was using win2k and didn't get the fatal. I ran into another issue
too.
Say you start up one instance and its holding the lock. Now start a
2nd
instance. In that 2nd instance call Ctrl-C. The script will then
call release
on the semaphore even though it never acquired the lock. Now while
the first
window is saying it still has the lock, you can start a 3rd instance
(2nd one is dead thought at this point) and it will acquire the lock.
I guess I didn't
catch that release does decrement the count even if you never called
wait.
Here is another modified version. (getting uglier by the moment)
So:
1. There is no way to guarantee that a process will decrement its
semaphore count since you can kill it immediately.
2. You can decrement a semaphore even if you have not waited on
it.
Perhaps this is part of the design though. Perhaps there are
situations
where one program would increment the lock and another would decrement
it.
I don't know if you would call it a "fatal flaw" or just the way they
work.
Regarding the wait though. I think using a timeout might be a good
idea
to go ahead and log when the semaphore can't be acquired. I didn't
see
any race condition using the timeout feature. You did say there was
one?
Im not sure what that race condition would be though????
[heres the best I could come up with in terms of being robust]
use strict;
use warnings;
use Win32::Semaphore;
my $screw_with = 0; # test case to release w/o acquisition
my $have_lock = 0;
my $sem;
foreach my $sig (qw/INT TERM/) {
$SIG{$sig} = sub {
print "signal: " . $_[0] . "\n";
print "release semaphore\n";
if ($sem and $have_lock) {
$sem->release;
$have_lock = 0;
}
elsif ($sem and !$have_lock and $screw_with) {
print "calling release on semaphore anyway\n";
$sem->release;
}
undef $sem;
exit 1;
}
}
my $sem_name = shift(@ARGV) ||
die "Usage: $0 <semaphore name>";
print "Getting semaphore [$sem_name]\n";
$sem = Win32::Semaphore->new(1, 1, $sem_name) ||
die "Couldn't create semaphore [$sem_name]\n";
print "Waiting to acquire lock [$sem_name]\n";
while (!$have_lock) {
my $result = $sem->wait(5000);
if ($result) {
$have_lock = 1;
}
else {
warn "timed out waiting for lock\n";
# at this point send an email or something
# because this sucks
}
}
print "Have lock [$sem_name]\n";
print "Press [Enter] to release lock.\n";
<STDIN>;
END {
print "release semaphore\n";
if ($sem and $have_lock) {
$sem->release;
$have_lock = 0;
}
undef $sem;
}