#1
  1. No Profile Picture
    Contributing User
    Devshed Loyal (3000 - 3499 posts)

    Join Date
    Jul 2003
    Posts
    3,403
    Rep Power
    594

    File::Pid Question


    I am trying to write a script that cannot be run concurrently with itself. I think I have a way using File::Pid but I am not sure of of a possible window of trouble.
    Code:
    my $pidfile=File::Pid->new({
            file=>"/var/run/kcbsjar.pid",
    });
    
    while ($pidfile->running) {
            sleep(5);
    }
    $pidfile->write;
    If I am doing this right what happens between the time the while loop exits and the 'write' occurs? It seems there is a possibility for another script to have also exited and the 2 running concurrently anyway. There must be a better way to block if $pid->running does not return false. Perhaps an outter safety loop?
    Code:
    my $pidfile=File::Pid->new({
            file=>"/var/run/kcbsjar.pid",
    });
    
    while ($pidfile->running) {
       while ($pidfile->running) {
            sleep(5);
       }
    }
    $pidfile->write;
    Does anyone have any alternative suggestions? TIA.
    There are 10 kinds of people in the world. Those that understand binary and those that don't.
  2. #2
  3. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    May 2007
    Posts
    765
    Rep Power
    929
    But what if one script starts running while another just broke out of the outer loop? So to be safe...
    Code:
    while( $pidfile->running ) {
      while( $pidfile->running ) {
        while( $pidfile->running ) {
          sleep 5;
        }
      }
    }
    ...which should hopefully be a clue that you need something a bit better to deal with the race condition.

    There's a module Sys::RunAlone on CPAN. I can't vouch for it personally, but it looks better maintained than File::Pid and deals with your problem at a higher level. It shouldn't be too difficult to patch the retry logic for an indefinite number of retries.

    If you want to roll your own, you need a mechanism where you can atomically test and set the indicator--anything that the OS won't let you do twice at once is fair game.

    flock() is the simplest route, but not all OS's are nicely behaved with respect to flock--you'll have to experiment to see if it fits your needs.

    sysopen() with the flags O_EXCL|O_CREAT is a classic way of doing it (creating a file failing if it already exists)--but you will need to clean up the file yourself and it may not work on non-*nix OSs.

    Another common method is to open a socket, bind it to a local address and listen & any future attempts to bind a socket to the same address will fail until the first closes.
    sub{*{$::{$_}}{CODE}==$_[0]&& print for(%:: )}->(\&Meh);
  4. #3
  5. No Profile Picture
    Contributing User
    Devshed Loyal (3000 - 3499 posts)

    Join Date
    Jul 2003
    Posts
    3,403
    Rep Power
    594
    Sys::Runalone looks good. Thanks.
    There are 10 kinds of people in the world. Those that understand binary and those that don't.

IMN logo majestic logo threadwatch logo seochat tools logo