I want to have my perl-gtk app query a database using DBI and display the query results. Some of the queries can take minutes to run and a naive implementation would mean all GUI interaction was blocked until the $dbh->execute returned. This seems to be a fairly common problem. http://mail.gnome.org/archives/gtk-perl-list/2004-November/msg00055.html http://mail.gnome.org/archives/gtk-perl-list/2005-August/msg00140.html In my case, I've cooked up a solution using ithreads. It worked fine for me (on win32). So I decided to abstract away all the thread related code into a separate package so that the main code will remain fairly clean (no thread related code in the main) Attached is the new (beta) package. MyThread.pm. An example is also attached. # --------------------------------- # USAGE: # --------------------------------- # The usage is fairly straightforward. Use the C<register_sql> to register a sql to be executed and a call_back to be called post-execution. You get to refer to this thing by a name so that you can call it later. $mythread->register_sql('<some name>', \&call_sql, \&call_back); Later on, this registered sql can be triggered by calling $mythread->execute('<some name>',[<list of parameters>]); $dbh and $sth cannot be 'shared' between threads. So I have to shuttle parameters and resultset between threads to get this thing going. Of course, I am using C<Storable qw(freeze thaw)> to exchange data structures. sub call_sql { my ($dbh, $sqlparams) = @_; my $params = thaw $sqlparams; # Don't forget to thaw my $sth = $dbh->prepare(qq{ # my complicated long query that takes a long time to complete select a.field2, b.field2 from table1 a, table2 b where a.field1 = b.field1 and a.field2 like ? }); $sth->execute('%'.$params->[0].'%'); # We HAVE TO load all required data into an array and send it back # Main thread does not have access to the $dbh and $sth... # Atleast I haven't figured out a way to 'share' these handles my @result_array; while (my @ary = $sth->fetchrow_array()) { push @result_array, \ ary; } return \ result_array; } The C<@result_array> that was created cannot be meddled with from the main thread. Instead, you'll get a frozen version of that through the call_back function. sub call_back { my ($result_array) = shift; @{$slist->{data}} = (); foreach my $x (thaw $result_array) { # Don't forget to thaw once more push @{$slist->{data}}, @$x; } } # --------------------------------- # This stuff works for me in my toy app on win32. If any one sees pitfalls with this approach please do let me know. Like I said before, I am still a newbie on threads(gtk2-perl). This is a problem which I 'have to' solve in my app and the approach seems good enough according to me. I can't use pipes because they don't behave quite well on win32. Also, spawning off a new process to do dbi query may be ugly. If no one sees issues with this approach, I'll load this into cpan under the name Gtk2::Ex::threads::DBI Regards, _Ofey.
Attachment:
MyThreadDBI.pm
Description: Binary data
Attachment:
mythread-usage.pl
Description: Binary data