I discovered Parallel::ForkManager the other day, and rejoiced. Unfortunately, in using it I ended up tearing my hair out due to a somewhat unrelated problem: the interaction of flock() and dup'd file descriptors in child processes.
(perl 5.6, FreeBSD 4.1.1-stable, but the principles apply equally elsewhere)

The problem:

Why?
In retrospect, this is easy- straight out of the perldoc for flock(), and also in `man flock`:

On systems that support a real flock(), locks are inherited across fork() calls, whereas those that must resort to the more capricious fcntl() function lose the locks, making it harder to write servers.

I fall into the first category: since the lock exists per-file, and the filehandle only has a reference to the lock, and since flock()'ing a file you already have a lock on succeeds, the children all get locks whenever they ask for them.

My solution
This is also not hard. Instead of opening the file in the parent, and flocking then appending in the children, I perform a standard locking append in the child whenever I want to append to a file:

# Warning: untested. If this were actual code, I would "use strict;" open (F, ">>$my_file"); flock (F, LOCK_EX) or die "no lock!"; seek (F, 0, 2); # In case someone wrote after open but before I got th +e lock print F $my_stuff_to_print; close F;

Why I don't like it
You can think of my particular case as similar to log file output. Multiple children need to append lines to one or more shared files without interrupting each other. Nothing is reading the files until it's known that all writing has completed and all child processes exit. I don't care about the order of the lines as long as no line is cut in half by any other line. In practice, the output is short enough not to cause any problems, but that's not good enough for those of us who are paranoid.

Because the reason I'm forking in the first place is to get better performance, I don't like the overhead of the open, flock, close calls every time I want to print a single short line to a file. Though I admit that this is a small portion of the total time spent in each child (as each child only outputs one line to any particular file).

Therefore,

The Question
Isn't there a better way? (read: more efficient than open, lock, close every time) If so, what is it?

Thank you for your time :)

Alan


In reply to Those fork()ing flock()ers... by ferrency

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.