I experimented a bit with threads and how to use them to perform tasks in
the background while still keeping the GUI responsive. This is a first
draft. Hopefully it will be useful to someone.
Demo with .gld file at:
<http://www.darserman.com/Perl/Loft/temp/FetchURL-threads.zip>
The program is used to fetch HTML from urls. The GET request is done in a
separate thread.
I tried various stuff but there was much segfaulting and variables lost
between the threads. I ended up using worker queues to pass control and
information between the threads.
The program begins by starting a thread and two queues (one for passing
urls to the getter thread, and one for returning the result.
my $oThreadBrowserGet;
my $oQueueBrowserGet;
my $oQueueBrowserGetReturn;
BEGIN {
$oQueueBrowserGet = Thread::Queue->new;
$oQueueBrowserGetReturn = Thread::Queue->new;
$oThreadBrowserGet = threads->new(
sub {
while(my $url = $oQueueBrowserGet->dequeue()) {
#... the GET is done here ... #
$oQueueBrowserGetReturn->enqueue(Dumper($res));
}
warn("Exiting getter thread\n");
});
}
The thread is started in a begin block to have it occur before the
Win32::GUI stuff is "use"d. I'm not sure, but I think that may be important.
The thread basically waits for an URL to be put in the request queue. When
one appears in the queue, the thread will GET the $url and put the
serialized GET result object in the return value queue.
If the passwd $url is undef, the while loop will terminate and the thread
will end.
When the thread is started, the GUI is loaded and the Dialog() main loop
entered. This is what happens in the event handler that gets the url:
sub ::btnFetch_Click { my ($win) = Win32::GUI::Loft::tglApp("winFetch") or
return(1);
my $url = $win->tfURL->Text();
$oQueueBrowserGet->enqueue($url);
while( ! $oQueueBrowserGetReturn->pending() ) {
Win32::GUI::DoEvents();
threads->yield();
}
my $VAR1;
my $res = eval( $oQueueBrowserGetReturn->dequeue() ); $@ and die($@);
$win->tfHttp->Text($res->headers_as_string());
$win->tfHtml->Text($res->content());
}
First the $url is put in the request queue. Then we wait for the return
value to show up in the other queue. The result object is deserialized and
used to populate the GUI controls (error checking omitted).
For some reason Storable::freeze and thaw produced segfaults, whereas
Data::Dumper works fine. Go figure.
It would be trivial to continously pass progress info back to the GUI to
update a ProgressBar control.
I think most of this could be fairly neatly encapsulated in a module so
there is a small amount of synchronization code in the application.
/J
-------- ------ ---- --- -- -- -- - - - - -
Johan Lindström Sourcerer @ Boss Casinos johanl AT DarSerMan.com
Latest bookmark: "TCP Connection Passing"
http://tcpcp.sourceforge.net/
dmoz: /Computers/Programming/Languages/JavaScript/ 12