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

Hi Perl Monks, I am developing a simple server health check script. It's basically a multithreading (20 threads) script with each thread sending a HTTP GET to my target pages and then print the status STDOUT (the cron will then redirect this STDOUT to a log file). The output (for each thread) is simply date/time, servername and status. I expect each line to be clean and tidy with only 3 fields, however very often I see that some lines are commingled together. It looks like as if one thread is in the process of printing and then somehow another thread just jumped in and printed in between the line. So I really want to look for a good way to lock the stdout, any thought? (ps. I already have $|++ in my script, didn't work; I also tried flock on STDOUT, didn't work either. The script was originally designed to run on 100 threads and I can't reduce it further because of performance issues) Please help. Thanks.

Replies are listed 'Best First'.
Re: multithread and STDOUT locking
by ikegami (Patriarch) on May 06, 2011 at 05:05 UTC

    I really want to look for a good way to lock the stdout,

    Not at all. You don't need to lock STDOUT, whatever that means. What you really really want is mutual exclusion. That can be done by obtaining a lock, but it can be a lock on anything, as long as all the parties lock the same thing.

    Since you're using threads, you can use a shared variable.

    my $stdout_mutex :shared; { lock($stdout_mutex); print ...; }

    Then again, if you're using threads, why are you using STDOUT at all. Why not use something like Thread::Queue instead?

Re: multithread and STDOUT locking
by BrowserUk (Patriarch) on May 06, 2011 at 09:12 UTC

    Somewhat easier than using lock() all over your code, is to wrap print in your own sub that does that for you:

    use threads; use threads::shared; my $sem :shared; sub tprint { my $tid = threads->tid; lock $sem; print "$tid: ",@_, "\n"; } sub twarn { my $tid = threads->tid; lock $sem; warn "$tid: ", @_; }

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: multithread and STDOUT locking
by locked_user sundialsvc4 (Abbot) on May 06, 2011 at 17:43 UTC

    Consider re-designing the script.   You don’t need n separate threads to check the health of n servers.   If already-developed open source tools like nagios cannot already do the job you’re building a solution for, then all you really need is (most likely...) one process that uses x socket(s) to send queries to y servers at least once every z seconds.   A simple select-based strategy will multiplex the incoming responses.

    Assuming that you do not simply discover that Nagios is already able to do what you want, without you actually having to write anything new, the actual design of the program that you write will become so trivial that I suspect it will not actually require multithreading at all.

Re: multithread and STDOUT locking
by Khen1950fx (Canon) on May 06, 2011 at 02:29 UTC
    Try:
    #!/usr/bin/perl use strict; use warnings; select STDOUT; $| = 1;
      Flushes aren't guaranteed to be atomic, so that's not guaranteed to work even if you using a single single print per message and the messages don't exceed 4k in size.
Re: multithread and STDOUT locking
by Anonymous Monk on May 06, 2011 at 22:07 UTC
    Does it really need to report anything but failures? I can understand spewing all the successes during development, but what's the point once you're done debugging? If it's still kicking out intermingled reports at that rate, you've got more fundamental problems to work on than your monitoring script.

    -Greg