Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Perl/Tk threading and/or cron job?

by PhysiciSteve (Initiate)
on Sep 20, 2011 at 11:32 UTC ( [id://926912]=perlquestion: print w/replies, xml ) Need Help??

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

Hi monks, I'm new to the concept of threading and am having trouble with a seemingly simple task. I have a working Perl/Tk script. What I want is a subroutine to periodically do something (query something from the terminal, do a calculation). I want this to happen in the background, once a minute, so that I can still have access to the GUI and its functions (this is the part I'm stuck on). The end result of that calculation would be to simply update a textvariable in a Label in the GUI once a minute. Any help would be appreciated!!!

Replies are listed 'Best First'.
Re: Perl/Tk threading and/or cron job?
by liverpole (Monsignor) on Sep 20, 2011 at 13:55 UTC
    Hi PhysiciSteve,

    It may help us more if you show what you've tried.

    Having said that, I'll give you a very simple example that may do more-or-less what you need. It starts a worker thread which calculates the localtime every minute, and passes that to the main thread through the shared variable $ltime. It's important to keep the Tk code separate from the thread code (because Tk is not thread-safe), which is why the textvariable '$lbl_label' was kept separate from $ltime, and only assigned from $ltime from within the Tk idle loop update_gui().

    You can, of course, change sleep 60; to a smaller interval to see it update more often:

    #!/usr/bin/perl -w # Libraries use warnings; use strict; use threads; use threads::shared; use Tk; use Tk::Font; # Shared variables my $ltime : shared = 0; # Globals my $lbl_label = "Started"; # Main Program my $thread = threads->create(\&worker_thread); $thread->detach; create_gui(); # Subroutines sub worker_thread { while (1) { $ltime = localtime(time()); print "Debug> In worker_thread(): Updated localtime to '$ltim +e'\n"; sleep 60; } } sub create_gui { my $mw = new MainWindow(-title => 'Thread example'); my $fr = $mw->Frame->pack(-expand => 1, -fill => 'both'); my $fnt = $mw->Font(-family => 'arial', -size => '12'); my $lbl = $fr->Label(-textvar => \$lbl_label, -background => '#ffe +fb5'); my $btn = $fr->Button(-text => 'Exit (ESC)', -background => 'cyan' +); $btn->configure(-command => sub { exit }, -font => $fnt); $lbl->configure(-font => $fnt); $lbl->pack(-side => 'left'); $btn->pack(-side => 'right'); $mw->bind("<Escape>" => sub { $btn->invoke }); $mw->repeat(1000 => \&update_gui); MainLoop; } sub update_gui { printf "Debug> In update_gui(): %s\n", time(); $lbl_label = $ltime; }

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

      I received a request today for running MCE with Tk and displaying a progress bar. Your post was very helpful. Thank you.

      use strict; use warnings; use threads; use threads::shared; use Tk; use Tk::Font; use Tk::ProgressBar; use MCE; # Shared variables my $percentage_completed : shared = 0.0; # Globals my $percentage_label = 0.0; my $download_label = "Completed...$percentage_completed%"; # Main Program my $mce_thread = threads->create(\&run_mce); run_gui(); # Subroutines sub indicator { my ($current_line, $total_lines) = @_; $percentage_completed = sprintf '%.1f', $current_line * 100 / $tot +al_lines; } sub run_mce { my $n=10; my $mce = MCE->new( max_workers => 1, init_relay => 0, sequence => [ 0, $n ], chunk_size => 1, user_func => sub { my ($mce, $i, $chunk_id) = @_; MCE::relay { indicator($i, $n) }; sleep 1; } )->run; } sub run_gui { my $mw = MainWindow->new(-title => 'Downloading...'); my $message = $mw->Message( -textvariable => \$download_label, -width => 130, -border => 2 )->pack(-side => 'top'); $mw->geometry('350x100'); $mw->resizable(1,0); my $progress = $mw->ProgressBar( -width => 15, -from => 0, -to => 100, -blocks => 50, #more block more smooth -gap => 1, #use 0 to get solid bar else use 1 -colors => [ 0, '#104E8B' ], -variable => \$percentage_label )->pack(-fill => 'x'); my $button = $mw->Button( -text => 'Cancel (ESC)', -command => sub { ($percentage_completed < 100.0) ? MCE::Signal::stop_and_exit('TERM') : $mw->destroy; } )->pack(-side => 'right'); $mw->bind('<Escape>' => sub { $button->invoke }); $mw->repeat(100 => \&update_gui); MainLoop; } sub update_gui { $percentage_label = $percentage_completed; $download_label = "Completed...$percentage_completed%"; }
Re: Perl/Tk threading and/or cron job?
by keszler (Priest) on Sep 20, 2011 at 13:53 UTC

    Tk::after - in particular:

    $widget->repeat(ms,callback) In this form the command returns immediately, but it arranges for callback be executed ms milliseconds later as an event handler. After callback has executed it is re-scheduled, to be executed in a futher ms, and so on until it is cancelled.
Re: Perl/Tk threading and/or cron job?
by zentara (Archbishop) on Sep 20, 2011 at 15:30 UTC
    There are a bunch of ways to do this, and using a thread has many ways of returning the data. Here is a way using a reusable thread, returning the data thru shared variables. I've included an Entry widget for you to get terminal input from.
    #!/usr/bin/perl use warnings; use strict; use threads; use threads::shared; # uses a reusable thread concept # enter any value in lower entry and the sin() will be # computed in the top entry my $val = 0; # textvariable return variable #create thread before any tk code is called my $data_in:shared = ''; my $data_return:shared = ''; my $go_control:shared = 0; my $die_control:shared = 0; my $thr = threads->new(\&excecute); use Tk; my $mw = MainWindow->new(); # catch window close button to clean up threads $mw->protocol('WM_DELETE_WINDOW' => sub { &clean_exit }); $mw->fontCreate('big', -weight=>'bold', -size=> 14 ); my $label = $mw->Label( -bg=> 'white', -width => 50, -font => 'big', -textvariable => \$val )->pack(); my $txt = $mw->Entry(-bg=>'lemonchiffon', -font => 'big')->pack(qw/-fi +ll x -pady 5/); $mw ->bind('<Any-Enter>' => sub { $txt->Tk::focus }); $txt->bind('<Return>' => \&do_calc ); # initiate a calc whenever a return is hit in the entry widget # you must read the shared var for the txtvar to update # a timer to update label my $timer = $mw->repeat(100,sub{ #every .1 second $val = $data_return; }); # a timer to initiate calculation my $timer1 = $mw->repeat(5000,sub{ #every 5 seconds &do_calc }); MainLoop; sub do_calc{ $data_in = $txt->get() || 0; # set a default value #wake up thread $go_control = 1; } sub clean_exit{ $timer->cancel; $timer1->cancel; my @running_threads = threads->list; if (scalar(@running_threads) < 1){print "\nFinished\n";exit} else{ $die_control = 1; $thr->join; exit; } } sub excecute{ # thread code while(1){ if($die_control){ print "thread finishing\n"; return} #wait for $go_control if($go_control){ if($die_control){ print "thread finishing\n"; return} #do your calculation here $data_return = sin( $data_in) .' '. time ; print "$data_in $data_return\n"; #done calculating, so turn thread back to sleep + $go_control = 0; }else{ select(undef,undef,undef,.25); }# sleep until awakened for next + command } return; }

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh
Re: Perl/Tk threading and/or cron job?
by PhysiciSteve (Initiate) on Sep 20, 2011 at 14:46 UTC
    THANKS Keszler and liverpole!!!!!! TK::After worked like a dream, exactly what I wanted. I first tried liverpoles solution which worked to a point, but I'm guessing because the loop never ends, the variable I want updated would not update in the GUI. I will investigate this further. Thanks again everyone
Re: Perl/Tk threading and/or cron job?
by PhysiciSteve (Initiate) on Sep 21, 2011 at 02:30 UTC
    Thanks zentara and liverpole, I've got the threading to work now and I think I've got my head around it. I appreciate the very informative responses!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://926912]
Approved by Corion
Front-paged by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (5)
As of 2024-04-19 02:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found