Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

flock question

by Odud (Pilgrim)
on Jun 27, 2000 at 13:28 UTC ( [id://19975]=perlquestion: print w/replies, xml ) Need Help??

Odud has asked for the wisdom of the Perl Monks concerning the following question:

I was writing some code to lock a file before I copied it and then did something with the copy so I had something like
use strict; use File::Copy; use Fcntl ':flock'; # import LOCK_* constants my $status_file = "/tmp/flocktest"; open(STATUS, "+<$status_file") || die "Can't open file"; flock(STATUS,LOCK_EX) || die "Can't lock file"; copy("$status_file","/tmp/foo");
However when I tested it by running more than one instance the locking didn't work. Eventually by trial and error I found out that I needed to change the copy to:
copy(\*STATUS,"/tmp/foo");
It looks as though copy is releasing the lock when given a filename as the first argument, but not when given a ref to the filehandle. Can anyone confirm this - and is it the expected behaviour?

Replies are listed 'Best First'.
Re: flock question
by ZZamboni (Curate) on Jun 27, 2000 at 18:20 UTC
    I can duplicate your problem. I modified your code like this for testing:
    use strict; use File::Copy; use Fcntl ':flock'; # import LOCK_* constants my $status_file = "/tmp/flocktest"; open(STATUS, "+<$status_file") || die "Can't open file"; print "getting lock...\n"; flock(STATUS,LOCK_EX) || die "Can't lock file"; print "waiting...\n"; sleep 10; print "copying file...\n"; # copy(\*STATUS,"/tmp/foo"); copy("$status_file","/tmp/foo"); print "finished copy, waiting....\n"; sleep 10;
    With the \*STATUS line uncommented, I get the following behavior (the two columns represent two terminals):
    % ./test.pl getting lock... waiting... % ./test.pl getting lock... copying file... finished copy, waiting... % waiting... copying file... finished copy, waiting... %
    And with the "$status_file" line uncommented, I get:
    % ./test.pl getting lock... waiting... % ./test.pl getting lock... copying file... finished copy, waiting... waiting... copying file... finished copy, waiting... % %
    The only explanation I can offer comes from the flock(3B) man page in Solaris:
    Locks are on files, not file descriptors. That is, file descriptors duplicated through dup(2) or fork(2) do not result in multiple instances of a lock, but rather multiple references to a single lock. If a process holding a lock on a file forks and the child explicitly unlocks the file, the parent will lose its lock. Locks are not inherited by a child process.
    This tells me that when copy() closes the file (even if it opened it using a different handle) the lock is lost. I may be completely wrong, though...

    --ZZamboni

      This is exactly the kind of material that I'd love to see more of in the Q&A section. This should be moved/dup'ed into the Files section.

      --Chris
Re: flock question
by Odud (Pilgrim) on Jun 27, 2000 at 14:32 UTC
    Another one where I post a partial answer to my own question. The problem seems to be that I have made an assumption about how filehandles behave. The code for Copy will open and close the file if given a filename but not if given a filehandle. This makes sense. What surprised me was that closing the file would release the lock. I was thinking that if I had obtained the lock by using filehandle XX then I would have to close it through XX to release the lock. I didn't do an explicit close and was expecting the lock to exist until the end of the script

    In summary the sequence of events is:

    opened as XX # by me
    locked as XX # by me
    opened as YY # by copy
    closed as YY # by copy and the lock is released

    Copy says "Note that passing in files as handles instead of names may lead to loss of information on some operating systems; it is recommended that you use file names whenever possible." - which is how I got into this mess in the first place
      To work around this, you can lock a semaphore file instead of the actual file you are copying.
      use strict; use File::Copy; use Fcntl ':flock'; # import LOCK_* constants my $status_file = "/tmp/flocktest"; my $semaphore = "/tmp/flocktest.sem"; open(SEM,">$semaphore") || die "Can't open file"; flock(SEM, LOCK_EX) || die "Can't lock file"; copy($status_file,"/tmp/foo"); unlink $semaphore; # only on unix close SEM;
        That's probably the simplest way around it - however when coding I tend to try to minimise the number of "things" that the script has to deal with. In this particular case a number of other files were being used but only one needed the lock and so it seemed logical to keep the lock with the file rather than create another object for the script to manipulate. Perhaps a good idea would be to come up with a generalised set of lock/unlock subroutines that I could use in all my scripts - I'll post it in snippets when I get it written.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://19975]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (4)
As of 2024-03-28 20:29 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found