in reply to Locking/unlocking program execution using a queue

The code below will do what you want.

Several things could be done to improve the code: 1) the pid could be output with the queue numer ($lock) so that the kill 0 recomened by RazorbladeBidet could be used; 2) better exit handling is needed so that improvement 1 is not needed; 3) the queue (countfile) could have a more robust structure.

use strict; use Fcntl ':flock'; use Time::HiRes qw ( usleep ); sub check_queue { my $lock = shift; my $top; open(FILE, "<countfile") || die; flock(FILE, LOCK_SH); seek(FILE, 0, 0); $top = readline FILE; flock(FILE, LOCK_UN); close FILE; return $lock == $top; } sub add_to_queue { my $lock = 0; if (open FILE, "+<countfile") { flock(FILE, LOCK_SH); seek(FILE, 0, 0); for (readline FILE) { $lock = $_; } $lock++; } else { open(FILE, ">>countfile") || die; } flock(FILE, LOCK_EX); seek(FILE, 0, 2); printf FILE "%d\n", $lock; flock(FILE, LOCK_UN); close FILE; return $lock; } sub remove_from_queue { my $lock = shift; my @procs = (); if (open FILE, "+<countfile") { flock(FILE, LOCK_SH); seek(FILE, 0, 0); for (readline FILE) { if ($_ == $lock) { next; } push @procs, $_; } flock(FILE, LOCK_EX); seek(FILE, 0, 0); truncate(FILE, 0) || die; print(FILE @procs); flock(FILE, LOCK_UN); close FILE; } else { die; } } my $done = 0; my $lock = add_to_queue(); eval { open LOCK, "./lockfile" || die; while (!$done) { flock(LOCK, LOCK_EX); last if check_queue($lock); flock(LOCK, LOCK_UN); usleep 50000; } print STDERR "Doing work on $lock ", scalar localtime, " \n"; # Do your work here sleep 3; print STDERR "Done working on $lock ", scalar localtime, " \n"; remove_from_queue($lock); flock(LOCK, LOCK_UN); }; if ($@) { remove_from_queue($lock); }
-- gam3
A picture is worth a thousand words, but takes 200K.

Replies are listed 'Best First'.
Re^2: Locking/unlocking program execution using a queue
by RazorbladeBidet (Friar) on Mar 31, 2005 at 13:23 UTC
    Thank you for pointing out that flaw, gam3 - I had figured the timestamp was more granular than that. I will try something like you have suggested instead.

    However, I'm thinking of several other options:
    1. Not requiring a program to remove itself from the queue. This will force the other programs to check to see if the process is still running, yes, but a process could always die, so, IMHO, I think the check_queue would always have to have a kill 0.
    2. Having a program signal the next process to wake up by sending an alarm and then bumping the sleep length up to a larger number. The wasted time between one process execution and another is less important than the wasted CPU cycles from waking up and checking on processes.
    Update: I just thought of this... what if instead of the single queue file, or creating a file named PID.lock and sorting by modification time, I were to use Time::HiRes' gettimeofday and name the file gettimeofday.PID.lock (with the values in there of course)

    Then... sorting the files numerically, should work, no?
    --------------
    "But what of all those sweet words you spoke in private?"
    "Oh that's just what we call pillow talk, baby, that's all."