Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Re: Win32::GUI window freezing, even with threading. (win32-gui-tk-thread-dequeue.pl, Thread::Queue::popnow/push)

by Anonymous Monk
on May 28, 2013 at 07:51 UTC ( [id://1035540]=note: print w/replies, xml ) Need Help??


in reply to Win32::GUI window freezing, even with threading.

win32-gui-tk-thread-dequeue.pl, Thread::Queue::popnow/push

If you write your Win32::GUI like this (like I discuss here and BrowserUk demonstrates) it should work the same way

#!/usr/bin/perl -- ## perltidy -olq -csc -csci=10 -cscl="sub : BEGIN END" -otr -opr -ce +-nibc -i=4 -pt=0 "-nsak=*" use strict; use warnings; use threads; use threads::shared; use Thread::Queue; Main( @ARGV ); exit( 0 ); sub Main { my $qin = Thread::Queue->new(); my $qout = Thread::Queue->new(); my $guithread = threads->create( \&tkgui, $qin, $qout ); ## don't wait for background downloading service / mechtitles threads->create( \&mechtitles, $qin, $qout ); $guithread->join; ## wait for gui to finish return; } ## end sub Main sub mechtitles { my( $qin, $qout ) = @_; threads->detach(); ## can't join me :) require WWW::Mechanize; my $ua = WWW::Mechanize->new( autocheck => 0 ); while( 1 ) { if( defined( my $url = $qin->popnow ) ) { $ua->get( $url ); my $title = eval { $ua->title }; $title ||= $ua->res->status_line; $qout->push( "$url =>\n $title\n" ); } threads->yield(); } } ## end sub mechtitles sub tkgui { my( $qin, $qout ) = @_; require Tk; require Tk::ROText; my $mw = Tk::tkinit(); my $pending = ""; my $l = $mw->Label( -textvariable => \$pending )->pack; my $t = $mw->ROText()->pack; my $b = $mw->Button( -text => 'enqueue another 3 example.com', )-> +pack; $b->configure( -command => [ \&q_pusher, $b, $qin, ], ); $b->focus; $mw->repeat( 500, ## ms [ \&pop_to_pending, $t, \$pending, $qin, $qout, ], ); $mw->MainLoop; return; } ## end sub tkgui sub q_pusher { my( $b, $qin ) = @_; $qin->push( 'http://example.com' ) for 1 .. 3; $b->configure( -state => "disabled" ); return; } sub pop_to_pending { my( $t, $pending, $qin, $qout ) = @_; if( defined( my $item = $qout->popnow ) ) { $t->insert( q!end!, join( '', $item ) ); } $$pending = 'Pending ' . $qin->pending; return; } sub Thread::Queue::push { goto &Thread::Queue::enqueue } sub Thread::Queue::popnow { goto &Thread::Queue::dequeue_nb }
  • Comment on Re: Win32::GUI window freezing, even with threading. (win32-gui-tk-thread-dequeue.pl, Thread::Queue::popnow/push)
  • Download Code

Replies are listed 'Best First'.
Re^2: Win32::GUI window freezing, even with threading. (Wrong solution)
by BrowserUk (Patriarch) on May 28, 2013 at 08:39 UTC

    That main sub is going to thrash the life out of the CPU (100% of one core (at least; possibly more) even when nothing is happening.)

    Moving to Tk instead of Win32::GUI to address the OPs problem is a mistake as well.

    The one, single advantage of Win32::GUi over the generic GUI frameworks, is that it was designed from the ground up to work in a multi-threaded environment.

    The mistake the OP is making is to try handing the responsibility of adding the data to the GUI list back to the event-loop thread. Whilst this is require of Tk and other 'portable' GUI frameworks -- because they are not thread-safe -- it is *NOT* a requirement of Win32::GUI.

    He can simple do away with the queue and move the $main_text_window->Append($tmptxt); into the same thread as the data is being gathered and allow the fact that pretty much every Win32::GUI Window function or method is actually implemented internally in terms of SendMessage(). Ie. the data to be append is is queued to the GUIs event loop via the process's system message queue to be processed in a timely fashion.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
    hr //i

      That main sub is going to thrash the life out of the CPU (100% of one core (at least; possibly more) even when nothing is happening.)

      How to fix that?

      Moving to Tk instead of Win32::GUI to address the OPs problem is a mistake as well.

      Well, it wasn't really meant to address the OPs problem, I just don't Win32::GUI much

      The mistake the OP is making is to try handing the responsibility of adding the data to the GUI list back to the event-loop thread.

      Which translates into what linechanges in OPs code?

      :)

        How to fix that?

        Don't use yield:

        threads->yield();

        That effectively equates to sleep( 0 ), which whilst it ensures that other threads get a timeslice, equates to:

        saveThreadContext; restoreThreadContext;

        when there are no other threads available to run; which is a cpu costly way to implement a delay.

        Replace it with Win32::Sleep( 33 ) will ensure that the gui remains responsive at speed faster than the eye can detect, but will drop the cpu usage of that thread to near 0.

        Which translates into what linechanges in OPs code?

        Should be as simple as:

        #######my $DataQueue = Thread::Queue->new(); ... #wait for data, print data to GUI textbox #######while(Win32::GUI::DoEvents() != -1) { ####### my $tmptxt = $DataQueue->dequeue(); ####### $main_text_window->Append($tmptxt); #######} Win32::GUI::Dialog(); sub mainloop { while (1) { #lots of page getting and number crunching goes here ########## $DataQueue->enqueue("some data"); $main_text_window->Append($tmptxt); } }

        Though that is untested.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
      This is how I set it up initially (because I didn't even know about threading). The data is added to the message queue to be processed by Win32::Gui to be processed when it gets around to it. My problem is whenever there is a WWW::Mechanize get call the gui would freeze. There's nowhere to add a DoEvents() call because the offending section of code is only one line (my $response = $mech->get( $url );) that takes a couple seconds to finish.

      A solution was posted below, but I'd love to learn more about Win32::GUI, if you're up to it (documentation and discussion is a bit sparse).
        There's nowhere to add a DoEvents() call because the offending section of code is only one line (my $response = $mech->get( $url );) that takes a couple seconds to finish.

        Using a thread to allow your GETs to run asynchronously from your GUI is a good idea.

        Using a queue to ship the data back to the gui thread for adding to the listbox is both unnecessary (you can add it from the same thread as you get it); and totally flawed if you use the blocking dequeue() call to fetch the data to be added, because that call blocks.

        You could use dequeue_nb(), but that creates its own set of problems.

        I'd love to learn more about Win32::GUI, if you're up to it

        I long ago gave up on Win32::GUI because the lack of documentation made every minor code addition or change a nightmare of searching for examples, and trial and error.

        As for what to use as an alternative, I mostly do without. But were I to have a need for a gui that could not be avoided, I probably plump for using HTML5 and the browser.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1035540]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (4)
As of 2024-04-25 05:59 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found