Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Is there a way to free the Tk MainLoop without getting into parallel programming?

by Takuan Soho (Acolyte)
on Jul 21, 2009 at 21:35 UTC ( [id://782092]=perlquestion: print w/replies, xml ) Need Help??

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

Hello monks!

Earlier this summer, I wrote a script to prepare large data files for some bioinformatics analysis. Since the number of options and input files to be specified by the user grew with the project, I decided to make a GUI using Tk. The GUI allows the user to specify the different input files and options, and then to launch the computation that the script was meant to do in the first place.

The problem is that, when the computation is launched, the interface freezes in the most inelegant way. And any progress message sent to the GUI is not shown until the computation is over (that makes for very useless progress messages!).

I've read that this freezing of the GUI is a common problem and the solution that is often proposed is to use parallel programming. I tried it briefly by replacing

&Launch_computation();

by

my $t1 = Thread -> new(\&Launch_computation()); $t1 -> detach();

On the surface, the problem was solved (the GUI was not jammed and progress messages were delivered timely). But I also faced new error messages that contains no reference to my code, like

Attempt to free non-existent shared string '_TK_RESULT_', Perl interpreter: 0x207ab410 at /usr/lib64/perl5/vendor_perl/5.8.8/x86_64-linux-thread-multi/Tk.pm line 250.

I am aware of the dangers and problems of parallel programming and I don't feel that I know perl well enough to do it... especially to do it well and safely. So I was wondering if you monks know of a way to free the Tk MainLoop without getting into parallel programming.

Thank you very much for your help!

Replies are listed 'Best First'.
Re: Is there a way to free the Tk MainLoop without getting into parallel programming?
by rcaputo (Chaplain) on Jul 21, 2009 at 21:57 UTC

    If the computation is CPU-bound, then you're pretty much required to offload it to another CPU core to keep the Tk MainLoop responsive. You can use threads, forking, or a separate computation server to offload the work from the CPU running Tk's MainLoop.

    You can also use $widget->update() to periodically update the status widget, if you don't mind Tk being less responsive during the computation. See the documentation for Tk::Widget for more information.

      Thank you for the hints!

      Indeed, using the parent widget "update" method after any text insertion (or any graphical change to the GUI for that matter) ensures that progress messages are delivered in time.

      It also makes the GUI somewhat responsive. Now, most of the time, an update call will be reached every two or three seconds. So, if the user wants to abort and press the exit button, it will exit within a couple of seconds. It's still not very elegant, but this is way better than having to wait for the entire computation to be done before the "abort" command is executed! If this is the best way to keep the GUI responsive without using parallel programming, I will be very happy to take this route.

      But I still see a problem with this solution, so I would like to submit it to the eyes of the Monastery. The remaining problem is: whether it takes 0.1 seconds or 10 seconds between two update calls depends upon the user's input files. That's because the time it takes for a chunk of code to execute (and hence, the time it takes between two update calls are executed) depends on the nature of the input. Can you, monks of the Monastery, think of a way to make update calls at fixed time intervals (let say once or twice per second) even though I have little control on the time it takes to execute a chunk of code?

      Thanks again for your help! It is very appreciated!

        It depends on the nature of the computations. If you're looping through that file yourself:

        my $t = time(); while (<$input_fh>) { process_a_line(); if (time() - $t >= 1) { $widget->update(); $t = time(); } }

        If the entire file is being atomically processed, then you'll need to get deeper into parallel programming.

Re: Is there a way to free the Tk MainLoop without getting into parallel programming?
by halfcountplus (Hermit) on Jul 21, 2009 at 21:57 UTC
    If you mean all the progress messages are appearing all at once at the end, that is because you are not using
    $mw->update;
    throw that into the processing loop after you do your ->Insert or whatever you are using to post the messages and they will appear one at a time ($mw being the main window handle).

    This is analogous to flushing output to a file stream, etc, etc, when it builds up in a buffer. You cannot set it "unbuffered", but you can do a flush using ->update. You do not need to get into threading or forking just for this.
Re: Is there a way to free the Tk MainLoop without getting into parallel programming?
by Marshall (Canon) on Jul 22, 2009 at 00:40 UTC
    Your model of a GUI is wrong - multi-thread is not needed here.

    The problem is that, when the computation is launched, the interface freezes in the most inelegant way. And any progress message sent to the GUI is not shown until the computation is over (that makes for very useless progress messages!).

    A GUI is UI event driven. User clicks on an "object"...something happens...meaning that a subroutine runs and potentially displays something. One of those things that can potentially happen is a GUI window with some status display. If the GUI UI is designed correctly, the UI won't "freeze". The designer of the the GUI should update the display per "unit of work".

Re: Is there a way to free the Tk MainLoop without getting into parallel programming?
by zentara (Archbishop) on Jul 22, 2009 at 14:07 UTC
    First of all, you are right about needing parallel processing, and the need to keep the event loop running. What is happening, is that Tk is NOT thread safe.... you can use it with threads ( with great care), but you cannot assume it will work with threads.

    What happens, is that when a thread gets spawned, it gets an exact copy of the parent thread, at the time of spawning. So you get some Tk code fragments, from the parent thread's mainloop, into the thread, and since Tk is NOT threadsafe, it raises havoc with the event system, as both threads try to run the event loop.

    The general rule, is to create your threads, before any Tk code is invoked. This is done by spawning your thread before you create the $mw in the parent thread. I usually use a sleeping thread thread model, where I can create numerous threads, which are help in a sleep loop until given a signal to go. After the sleeping threads are created, go ahead and make your Tk control GUI, and use shared variables to signal the child threads to start/stop/return etc.

    See PerlTk on a thread... and Tk-with-worker-threads for example..... this has been discussed many times before, and googling for "perl tk threads" will yield many code examples.

    BTW, Gtk2 has better built-in thread safety, if you want to move up to it.

    P.S. There is a module I saw recently( I didn't test it), that supposedly will only copy relevant code, when creating threads avoiding this copy-on-create problem.... I don't know if it works with Tk, or even at all, but its worth a search for...... me...I'm on vacation...:-)


    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku
Re: Is there a way to free the Tk MainLoop without getting into parallel programming?
by Anonymous Monk on Jul 22, 2009 at 16:38 UTC
    Depending on how long your calculations take the 'update' method mentioned above will keep the visual changes flowing, but your app will still appear to be unresponsive to mouse and keyboard events. As an alternative, if you can rewrite your routine to take smaller bites out of the computation when called repeatedly, then when the routine is finished with a bite, but not the complete calculation, it could put an event in the Tk event queue to call another iteration of itself. Your calculation may take slightly longer this way, but your UI would appear much more responsive.

Log In?
Username:
Password:

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

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

    No recent polls found