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

I have a gui running and a process being started by a thread. Since I am using Tk, I have to declare a thread above Tk:
use threads; use threads::shared; my $thr=threads->create(\&serverRequest); use Tk; #bunch of stuff has to happen before the thread starts #running ... $thr->detach; while(flag that the thread is requesting){ &updateGUI; }
The problem is that the thread starts running not from the detach, but from the create (or new). When I put it below use Tk, it starts from detach, but crashes because Tk is not thread safe. Is this a bug or am I missing something?

Replies are listed 'Best First'.
Re: Perl Threads
by zentara (Cardinal) on Feb 11, 2012 at 09:33 UTC
    See Re: Perl Tk and Threads. For the problem of the thread starting with new(), you can control threads manually by putting them in a loop controlled by a go/stop shared variable, see Re: Perl/Tk threading and/or cron job? for example.

    If you are using one of the latest versions of threads, you can also make use of Thread::Semaphore. Directly from "perldoc threads".

    use threads; use Thread::Semaphore; sub thr_func { my $sema = shift; # Thread 'suspend/resume' signal handler $SIG{'STOP'} = sub { $sema->down(); # Thread suspended $sema->up(); # Thread resumes }; ... } # Create a semaphore and pass it to a thread my $sema = Thread::Semaphore->new(); my $thr = threads->create('thr_func', $sema); # Suspend the thread $sema->down(); $thr->kill('STOP'); ... # Allow the thread to continue $sema->up();

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh
Re: Perl Threads
by wrog (Friar) on Feb 11, 2012 at 01:29 UTC
    First of all, the thread is always supposed to start running from the create, so if there's anything that needs to happen before the thread starts running, it should be before the create. It may be that there are aspects of your environment (e.g., you only have one CPU) that fortuitously keep the thread from running right away, but this will be phase-of-the-moon stuff that you will not be able to rely on in general.
    but crashes because Tk is not thread safe
    If a package is not thread safe, it's just not thread safe, period. The moment you create a second thread all bets are off.

    And this would be especially true of something big and complicated like Tk that has its own event loop and probably has other random things going on in the background.

    See, when you call create, it creates an entirely new Perl interpreter to run the thread, and every variable you have declared up to that point — including every variable declared in any file that you have loaded up to that point — is duplicated. If Tk is loaded, everything in every package there is going to get duplicated too, and it's not expecting to be. In particular, the C code that's part of the implementation of Tk gets thrown for a loop; and thus, crash.

    So, the only way your code in its current form has any chance of working is to make sure all Tk-related stuff is only ever even loaded by one interpreter. Not only do you not do use Tk, you have to ensure that everything that even mentions Tk (including, I suspect, what you have in the "#bunch of stuff that has to happen before the thread starts running") is buried inside a subroutine that starts with require Tk and that subroutine must only be invoked after you've created the last of the various extra threads that you need.

    Which means you have no choice but to have the serverRequest thread starting first. Moreover, since that thread will not be able to reference anything in Tk Land directly, whatever UI state it cares about will need to be communicated via shared variables and you'll need event handlers in Tk Land to keep those variables updated. You'll probably also need a semaphore/whatever for the serverRequest thread to wait on until the Tk stuff is ready (and likewise have an event handler in the main thread to trigger it at the appropriate time).

    And if this sounds like a mess, that's because it is. It's one thing if you're doing stuff with multiple threads where the other threads have nothing to do with the UI. But if you find yourself needing multiple threads interacting with the UI, then you're probably doing something wrong and will need to take a closer look at Tk to see if there's some other better way of doing it.

Re: Perl Threads
by Eliya (Vicar) on Feb 10, 2012 at 18:53 UTC
    ...I have to declare a thread above Tk

    use is executed at compile time, so putting use Tk below the my $thr=... statement does not have the effect of executing it afterwards...  See require.

      Same problem. Even if I use require and then import.