in reply to PerlTk on a thread...
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.
|
|---|