in reply to PerlTk on a thread...

Hi Wiggins,

Tk is not thread safe, so you should not expect to be able to manage a gui from two threads in the same process.

However, that shouldn't stop you from doing ALL gui management from within one thread (preferrably the parent), and setting up a worker thread to handle otherwise potentially-blocking actions (such as LWP fetches).  For that, you may want to look at using threads::shared.

To do this, construct the thread before setting up the gui.  I've created an example program for you which illustrates this:

#!/usr/bin/perl -w # Always use 'strict' and 'warnings' use strict; use warnings; # Libraries use threads; use threads::shared; use Thread::Queue; use Tk; use Tk::ROText; # Globals my $rotext = 0; # The Read-only text widget my $n_lines_waiting: shared = 0; # Message passing between thre +ads my $p_queue = Thread::Queue->new(); # Construct message 'Queue' #################### ### Main program ### #################### # Startup worker thread my $gui_thr = threads->create(\&worker_thread); # Only *now* is it safe to construct the GUI, from the parent thread gui(); + ################### ### Subroutines ### ################### # This subroutine is ONLY called from the parent thread sub gui { my $mw = MainWindow->new(); my $top = $mw->Frame()->pack(-expand => 1, -fill => 'both'); my $bt = $top->Button(-bg => 'skyblue', -text => "Exit"); $bt->configure(-command => sub { $mw->destroy() }); $rotext = $top->ROText(-bg => 'white'); $rotext->pack(); $bt->pack(); $mw->repeat(1000 => \&main_loop); MainLoop; } sub main_loop { if ($n_lines_waiting) { fetch_worker_data(); } } sub fetch_worker_data { for (my $i = 0; $i < $n_lines_waiting; $i++) { my $line = $p_queue->dequeue(); $rotext->insert("end", "$line\n"); } $rotext->insert("end", "--- End of $n_lines_waiting line(s) ---\n" +); $rotext->see("end"); my $mw = $rotext->toplevel(); $mw->update(); $n_lines_waiting = 0; } # This subroutine is ONLY called in the worker thread sub worker_thread { while (1) { sleep 3; worker_simulate_data(); } } sub worker_simulate_data { my $nlines = int(rand(10)); ($nlines > 0) or return; my $timestamp = localtime(time); for (my $i = 0; $i < $nlines; $i++) { my $idx = $i + 1; my $line = "[$timestamp] Random line of text #$idx"; $p_queue->enqueue($line); } $n_lines_waiting = $nlines; }

The subroutine worker_simulate_data is called by the worker_thread subroutine every 3 seconds, and creates from 0 to 9 lines of data, which are then queued using Thread::Queue.  Finally, the shared variable $n_lines_waiting is set to the number of lines waiting in the queue.

The parent thread gets the signal of how many lines are waiting via $n_lines_waiting, pulls this number of lines out of the shared queue, and writes them to the ROText window $rotext.

Note that the worker thread only writes new data if $n_lines_waiting is zero (otherwise there are lines waiting which haven't been read by the parent thread yet).

Of course, you are free to do other operations within the main_loop, as well as modify worker_thread so that it uses real-life data rather than a simulation.


s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/