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

Can someone please tell me why following script hangs. Main thread creates a thread (say "secondThread"). secondThread tries to create a thirdThread after sleeping for a while and that is where it hangs (i mean thirdThread is never created). Interesting thing is when main main thread prints something after I enter something on console the thirdThread is created. I am using ActiveState perl 5 on Windows (tried on XP and 7).

#!perl -w use strict; use threads; use Thread; use threads::shared; sub thirdThread { threads->detach(); printf "[%d] Third thread started\n",threads->tid(); } sub secondThread { threads->detach(); while(1) { sleep 2; printf "[%d] Going to start a new thread\n",threads->tid(); threads->create(\&thirdThread); } } threads->create(\&secondThread); while(<STDIN>) { print "CMD: ",$_,"\n"; if($_ eq "quit\n") { last; } }

Replies are listed 'Best First'.
Re: Thread create hangs
by BrowserUk (Patriarch) on Sep 27, 2010 at 21:30 UTC
    and that is where it hangs ... Interesting thing is when main main thread prints something after I enter something on console the thirdThread is created.

    Because Perl is serialising access to STDIN. Probably because it needs to clone STDIN for the new thread, and can't do that while it is in an input state. (Though I do not understand why not!)

    Ie. Because your main thread has STDIN in a input state here: while(<STDIN>), Perl won't create a new thread until the input state is completed. Hence why the thread "runs" once you hit enter.

    I thought for a moment that this synchronisation might be a MS CRT thing, but doing the equivalent in C, and it doesn't happen:

    #include <windows.h> #include <stdio.h> void thread2( void *p ) { printf( "[%d] Running\n", GetCurrentThreadId() ); } void thread1( void *p ) { while( 1 ) { Sleep( 2000 ); printf( "[%d] About to start a new thread\n", GetCurrentThread +Id() ); _beginthread( thread2, 0, 1 ); } } void main( void ) { char buf[ 1024 ]; _beginthread( thread1, 0, 1 ); while( gets( buf ) ) { printf( "CMD: %s\n", buf ); } return; } /* output C:\test>junk2.exe [3120] About to start a new thread [5168] Running [3120] About to start a new thread [3944] Running [3120] About to start a new thread [6016] Running fred CMD: fred [3120] About to start a new thread [6996] Running [3120] About to start a new thread [6980] Running */

    I think this is a bug; and I do not have an immediate workaround for it either.


    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: Thread create hangs
by BrowserUk (Patriarch) on Sep 28, 2010 at 19:32 UTC

    Here's a less than satisfactory, but never the less, working work-around:

    #! perl -slw use strict; use 5.010; use threads; use threads::shared; use Term::ReadKey; sub readline_NB { state $buf; my $timeout = shift; my $rv; my $chr = ReadKey( $timeout ) // ''; if( $chr eq chr(13) ) { $rv = $buf; $buf = ''; return $rv; } else { $buf .= $chr; return; } } sub thirdThread { printf "[%d] Third thread started\n", threads->tid(); } sub secondThread { while( 1 ) { sleep 2; printf "[%d] Going to start a new thread\n", threads->tid(); threads->create( \&thirdThread )->detach; } } threads->create( \&secondThread )->detach; while( 1 ) { if( my $input = readline_NB( 0.1 ) ) { print "CMD: ", $input; last if $input eq 'quit'; } else { Win32::Sleep 0.1; } } __END__ c:\test>junk48 [1] Going to start a new thread [2] Third thread started [1] Going to start a new thread [3] Third thread started CMD: fred [1] Going to start a new thread [4] Third thread started [1] Going to start a new thread [5] Third thread started CMD: bill [1] Going to start a new thread [6] Third thread started CMD: quit

    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.
      Great! Thanks for workaround. I would submit the bug to ActiveState. I have just started learning Perl. I thought ActiveState is stable because it is used extensively but this bug has changed my opinion.
        threads is a module, it is not developed by ActiveState
Re: Thread create hangs
by locked_user sundialsvc4 (Abbot) on Sep 28, 2010 at 13:52 UTC

    The OP should probably re-consider this entire approach... unless it is just an experiment to see how to do it.   Threads generally can’t meaningfully share resources such as “the terminal,” because of course there is only one of them.   If you are going to spawn multiple threads to do anything at all, be very sure that they will not contend with one another.   A thread should be created for a “purpose” or a “role,” not for a “task” or “request.”

      Threads generally can’t meaningfully share resources such as “the terminal,” because of course there is only one of them.

      Twaddle! Forked processes share "the terminal" all the time. Every time you type a piped command those processes are sharing a common console.

      With threads, you have the advantage that coordinating that shared access is trivial. Just a shame about the bug.


      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.
      Thanks for replying. I don't think the terminal is being shared among threads in above program. Only main thread is trying to read from terminal. Imagine a situation where you want to create a server where one thread listens for new connections (secondThread in this case) and spawns threads to handle clients (thirdThread in this case), and main thread waits for user's command e.g "exit" to gracefully terminate the server. I understand if there is bug in ActiveState Perl one will have to re-consider the approach otherwise this approach is quite common in real world. thx