Search code examples
perlfile-iofile-locking

Is there a way to create a file that is locked at the point of creation, in Perl?


I need to create a file that is locked against reads, at the point of creation, so that other processes that may go looking for this file do not start reading it, before it has been completely written.

I know that I can create and then lock it, but I'm concerned that this leaves me open to a race condition.

Or am I worrying about nothing here? If I have a file open for writing and then open it for reading with another process, will the reading process never see an EOF until the writing process closes the file?


Solution

  • There's is a race condition with > and >>, but it can be circumvented using +<.

    # >
    open(my $fh, '+<', $qfn) or die $!;
    flock($fh, LOCK_EX) or die $!;
    truncate($fh, 0) or die $!;
    ...
    
    # >>
    open(my $fh, '+<', $qfn) or die $!;
    flock($fh, LOCK_EX) or die $!;
    seek($fh, 0, SEEK_END) or die $!;
    ...
    

    There is also a race condition in the scenario you describe.

    Writer                       Reader
    =========================    =========================
    - opens file
                                 - opens file
                                 - locks file
                                 - obtains lock on file
    - locks file [blocks]        - reads the file [empty]
                                 - closes and unlocks file
    - obtains lock on file
    - writes to file
    - writes to file
    - closes and unlocks file
    

    A common strategy to avoid this problem is to have the writer

    1. create the file in a temporary directory, and then
    2. rename the file into the directory the reader monitors when the file is complete.

    rename is an atomic action, so the file will appear fully formed in the directory the reader monitors. This requires the cooperation of the writer, but the best solutions will.