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

If I have some perl code that flocks a file with LOCK_EX and then forks, does the parent or the child get the lock (this is on linux/x86)? Something like:
use Fcntl ':flock'; use POSIX ':sys_wait_h'; my $fh; open($fh, 'somefile.txt'); flock($fh, LOCK_EX); my $pid = fork(); if ($pid == 0){ #this is the child...does it have the lock? #do some stuff.... exit; } elsif (!defined($pid)) { die "Couldn't fork: $!"; } else { #this is the parent...does it have the lock? waitpid($pid, &WNOHANG); }

Replies are listed 'Best First'.
Re: Fork + Flock = Who Gets the Lock?
by salva (Canon) on Jun 03, 2005 at 19:44 UTC
    running man flock on my Linux box tells...

    Locks created by flock() are associated with a file, or, more precisely, an open file table entry. This means that duplicate file descriptors (created by, for example, fork(2) or dup(2)) refer to the same lock, and this lock may be modified or released using any of these descriptors. Furthermore, the lock is released either by an explicit LOCK_UN operation on any of these duplicate descriptors, or when all such descriptors have been closed.

    ... so they are shared!

      Thanks! So if they share the lock, then would it be safe to say that if the child process closes the file handle then it will no longer have a lock, but the parent will?
        yes, the lock being released only "when all such descriptors have been closed" (in the absense of an explicit unlock) means exactly that.
        yes!

        BTW, I think this behaviour is very OS dependant

Re: Fork + Flock = Who Gets the Lock?
by ikegami (Patriarch) on Jun 03, 2005 at 19:45 UTC

    The locks are merely advisory, so both the parent and the child (and all other processes) can still read and write from the file. Therefore, the question then boils down to: Who should unlock the file? On FreeBSD, that's apparently up to you to decide:

    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.

      Hrrm, that's weird because (quoting from APUE 1st ed, p373):

      2. Locks are never inherited by the child across a fork. This means that if a process obtains a lock and then calls fork, the child is considered "another process" with regard to the lock that was obtained by the parent. The child has to call fcntl to obtain its own locks on any descriptors that were inherited across the fork. . . .

      And I just looked and OS X has the same verbiage as FreeBSD does (not to surprising, of course :). This may be a BSD-vs-POSIX-vs-SysV thing; at any rate check your OS's flock(2) docs. (Heh. "flock doc" . . .)

      --
      We're looking for people in ATL

        well, this way, the programmer can decide where he wants to use the lock, on the parent or on the child, and just close the file on the other process (or not use it at all).
Re: Fork + Flock = Who Gets the Lock?
by tlm (Prior) on Jun 03, 2005 at 19:49 UTC

    AIUI, the parent and child processes are one and the same up the point of forking, so whatever "ownership" of the lock there is (if one can call it that) is held by both processes. But I think this is not the best way to think about it. The important thing is that the a file is marked by the OS as being locked (it doesn't matter by whom) so that other processes (those who are playing nice anyway) that attempt to get a lock while the first lock is in effect will use the failure inability to obtain the lock as an indication that they should wait because the file is "busy".

    Update: Fixed the misleading wording (thanks to salva for pointing it out). Indeed, whether the request for the lock fails or blocks (both of which I'm referring to collectively as "inability to obtain the lock"), and ultimately the way the program "waits" until the file is no longer busy, depends on the specific arguments given to flock, as salva points out. And while I'm dotting my i's and crossing my t's, all of the above refers to Unix flocking. I know nothing about how any of this works on Windows.

    the lowliest monk

      by default, flock doesn't fail when another process already has a lock on the file, it just waits until all the incompatible locks are gone.

      To make flock non blocking you have to use the LOCK_NB flag.

Re: Fork + Flock = Who Gets the Lock?
by ivancho (Hermit) on Jun 04, 2005 at 04:06 UTC
    the above discussion slightly confused me, so I decided to conduct a few tests of my own.

    amusingly enough, both Perls on Cygwin and WinXP hang on the following:

    #! perl -lw use strict; use Fcntl ':flock'; open my $fh, "<", "whatever" or die $!; flock $fh, LOCK_EX; flock $fh, LOCK_EX;

    well, ok, let's try on a better OS.. so, Solaris ( don't flame me, that's the only other I have lying around )

    this:

    open my $fh, "<", "whatever" or die $!; flock $fh, LOCK_EX; my $pid = open my $pip, "|-"; die "open(): $!" unless defined $pid; if ($pid > 0) { close $pip } else { flock($fh,LOCK_EX); print "got the lock"}
    is perfectly fine.. but try to change the open to ">", and the whole thing hangs, clearly as the child waits for the exclusive lock, while the parent waits to close the child... the reverse
    if ($pid > 0) { flock($fh,LOCK_EX); print "got the lock" } else { sleep(20) }
    works like a charm, the parent grabs the exclusive lock straight away...

    Moral: flocks are weird. I will not fork a flock (or flock a fork), unless in dire need of weird behaviour..
    update: fixed open fail check, thanks to spotter tlm

Re: Fork + Flock = Who Gets the Lock?
by graff (Chancellor) on Jun 04, 2005 at 23:05 UTC
    I think this is one of those cases where it could make a difference if we knew: "Why do you ask?"

    In particular, if only the child is going to be using the locked file handle, why would you need or want to open/lock the file before forking? You could just do this in the child process after the fork, and not worry about what happens across a fork. The same reasoning would apply if only the parent were doing stuff with the file in question. OTOH, if the plan is for the parent to do something with the locked file either before or after the child works on it, why even do the fork in the first place (unless there is enough other stuff to do, not involving the file, that makes the fork worthwhile)?

    Now, if your idea is that both child and parent are going to be doing things "in parallel" with this one locked file, you're likely to run into problems whose symptoms might be really strange, unpredictable and hard to debug. One of the main reasons for file locking in the first place is to keep concurrent processes from trampling each other when working with the same external resource.