The problem is grounded in the duplication of state that occurs with threads. When you spawn a thread, the thread gets a copy of all the state that exists in the thread that spawned it. This includes the state associated with file handles. This necessary to allow each thread to have it own filepointer position, buffers etc. independant of other threads filepointers and buffers.

At the point in your program where you spawn your thread, FILE has not been opened, and that it the state that gets copied. Hence, when you later try to close that filehandle you get the " Bad file descriptor at ... " error. This can be more clearly demonstrated by the following simplification of your program:

#! perl -slw use strict; use threads; sub t{ sleep 10; close FILE or die "Error closing FILE : $!" }; threads->new( \&t )->join; open FILE, '>', 'junk.dat' or die "junk.dat: $!"; print FILE 'Some stuff ', $_ for 1 .. 1000; #threads->new( \&t )->join;

If you run this as is, the thread gets started and immediatly sleeps for 10 seconds, giving the first thread the chance to open the FILE and write some stuff to it. When the 10 seconds is up, the thread attempts to close the FILE handle, and fails with the "Bad file descriptor" error because no file descriptor was associated with FILE when the thread was spawned.

If you comment out the first thread->new line, uncomment the second, and re-run the program, you'll find that the close is successful because FILE has a descriptor associated with it at the point of the spawn.

Ultimately, the problem comes down to one of bad design on behalf of your program. It is generally not wise to share resource, not even (or maybe especially) global resources like filehandles between threads. At least not without giving careful thought to the ramifications of doing so.

For your particular purpose, I would code the application something like this:

#! perl -slw use strict; use threads; use threads::shared; my $filename = "/tmp/input.log"; $outputdir = "/var/log/"; my $first_event = 1; my $position = 0; my $time = time(); my $timerFlag : shared # Define Timer sub timer { my $counter = 0; while (1) { sleep(1); if ($counter >= 60) { $counter = 0; lock $timerFlag; $timerFlag = 1; } $counter++; } } my $thr1 = threads->new(\&timer); # Spawn the thread open(TAIL, "tail --follow=name $filename|") or die "TAIL : $!"; my $outputfile = $outputdir . "log-". time(); open(FILE, "> $outputfile") or die("Can't open $outputfile to write to $!"); while (<TAIL>) { if( $timerFlag ) { lock $timerFlag; $timerFlag = 0; close FILE or die $!; $outputfile = $outputdir . "log-". time(); open(FILE, "> $outputfile") or die("Can't open $outputfile to write to $!"); } print( FILE $_ ) or die "Writing to FILE : $!"; }

Note: That is just example code to demonstrate the idea, not fully thought through or tested.


Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"Think for yourself!" - Abigail
"Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon

In reply to Re^3: Threading and File Handles by BrowserUk
in thread Threading and File Handles by matt.schnarr

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.