For the Win32::GUI guirus (spelling intended:-)), is Win32::GUI thread
safe?
I'm not a guru, but if you want a rough answer:
Yes, Win32::GUI is thread safe. Well, sort off:) Rob May and I have had an
exchange of emails about how to make Win32::GUI thread programming easier,
after some testing we came up with some interesting results.
The first thing to mention is that the main limiting factor is perl itself.
Only the 5.8.x codeline is worth considering, with the latest version
(5.8.7) being the best to use.
The core of Win32::GUI is indeed thread safe - all the XS/C code - (well, we
have yet to find an issue). Rob found that a couple of lines of perl code is
needed within Win32-GUI to make itself fully thread safe. This can be
achieved with the following code:
use strict;
use warnings;
use 5.007002; # Perl 5.7.2 or higher needed for CLONE_SKIP
use threads;
use threads::shared;
use Win32::GUI();
# make Win32::GUI threadsafe
sub Win32::GUI::CLONE_SKIP {1};
sub Win32::GUI::Timer::CLONE_SKIP {1};
The CLONE_SKIP function would need to be added for all Win32-GUI objects
that you would use. New versions of Win32-GUI would have these functions
already added.
Win32-GUI is surprising robust with threading, as each spawned thread can
create it's own windows, with the creating thread responding to events for
that window. The major limitation is that you can't change the thread that
handles the event for a window. For example, if thread A creates a window,
you can't make thread B respond to events for that window. With this
limitation in mind, you can do things like:
#!perl -w
$|=1;
use strict;
use warnings;
use 5.007_002; # Perl 5.7.2 or higher needed for CLONE_SKIP
use threads;
use Win32::GUI();
# Make Win32::GUI thread-safe
sub Win32::GUI::CLONE_SKIP {1};
my $count=1;
my $numberOfWorkers=5;
my $main=MainWindow('main',$count++);
my $thr;
for (1..$numberOfWorkers) {
$thr = threads->create(\&Worker2,"worker $_",$count++);
$thr->detach();
}
$main->Show();
Win32::GUI::Dialog();
sub MainWindow {
my ($name, $number)[EMAIL PROTECTED];
my $mw = Win32::GUI::Window->new(
-title => "$name thread window",
-pos => [400,400],
-size => [300,200],
);
$mw->AddTextfield (
-name => 'Log',
-height => 80,
-width => 160,
-top => 4,
-left => 4,
-multiline => 1,
-addstyle => 2097152,
-addstyle=>4096,
);
return $mw;
}
sub Worker2 {
my ($name, $number)[EMAIL PROTECTED];
my $mw = Win32::GUI::Window->new(
-title => "$name thread window",
-pos => [100,100],
-size => [300,200],
);
$mw->AddButton(
-text => 'Do some work in this window',
-pos => [114, 10],
-height => 20,
-onClick => \&Job,
);
$mw->AddTextfield (
-name => 'Process',
-height => 20,
-width => 35,
-top => 2,
-left => 20,
);
$mw->Process->Text($number);
$mw->Show();
#the thread enters the Dialog phase
Win32::GUI::Dialog();
}
sub Job {
my $self=shift;
my $parent=$self->GetParent();
my $id=threads->tid();
#do some work for 2 seconds
Win32::Sleep(2000);
my $item=$parent->Process->Text();
print "finished $item in thread $id";
}
Which creates 6 windows, each one running in it's own thread. You'll need
the latest version of Win32-GUI to run this example.
Rob May has developed some very interesting code that will make the
communication between threads that use Win32-GUI objects so easy to do, that
we'll all be building threading win32-gui apps in our sleep:)
Cheers,
jez.