Hi Garden Dwarf,
Based on your code, the following runs for me on a Windows 7 VM running Perl 5.26.1. Workers persist in the background. Two queues (inbound and outbound) are used. Due to lack of time, I apologize for not displaying to the terminal. The goal was seeing text display in the windows dialog. And yes, there you go. :)
I added a state variable ($running) in the event a long running job so not to impact the main app.
#!/bin/perl
# Win32::GUI and threads issue
# https://www.perlmonks.org/?node_id=1228580
use strict;
use warnings;
# One may run threads + MCE::Shared. This works very well.
# Why MCE::Shared one might ask? Well, it handles serialization
# of data objects automatically. E.g. passing array refs.
use threads;
use MCE::Shared;
my $queue_in = MCE::Shared->queue();
my $queue_ou = MCE::Shared->queue();
my $t_amount = 3; # Amount of threads to create
my $running = 0;
my $textbox;
my $win;
# Important, spawn threads early before loading Win32::GUI.
threads->new('producer') for 1..$t_amount;
# Run the main app or consumer afterwards.
consumer();
# Voila :)
exit;
sub consumer {
require Win32::GUI;
# Initialize window
$win = new Win32::GUI::Window(
-left => 0,
-top => 0,
-width => 300,
-height => 300,
-name => "Window",
-text => "Test",
);
$win->InvalidateRect(1);
$textbox = $win->AddTextfield(
-name => "Output",
-left => 5,
-top => 5,
-width => 275,
-height => 255,
-text => "",
-multiline => 1,
);
# Start application (calls draw_Timer)
$win->AddTimer('draw', 333);
$win->Show();
Win32::GUI::Dialog();
}
sub producer {
$SIG{QUIT} = sub {
threads->exit();
};
while ( defined ( my $next_args = $queue_in->dequeue ) ) {
my ( $c, $begin, $end ) = @{ $next_args };
my @ret = compute($begin, $end);
sleep 2; # simulate a long running process
$queue_ou->enqueue([ $c, @ret ]);
}
}
sub Window_Terminate {
$queue_in->end();
$_->kill('QUIT') for threads->list;
-1;
}
sub draw_Timer {
# Enqueue range of computation to background threads
if ( $running == 0 ) {
$running = 1;
foreach my $c (1..$t_amount) {
my $d = $c - 1;
$queue_in->enqueue([ $c, $d*10, $d*10+10 ]);
}
}
# Obtain data once background threads have completed
if ( $running == 1 && $queue_ou->pending == $t_amount ) {
$running = 0;
my @ordered_ret;
foreach my $c (1..$t_amount) {
my $ret = $queue_ou->dequeue();
my $c = shift(@{ $ret }) - 1; # array-based-zero
$ordered_ret[$c] = "";
foreach my $data (@{ $ret }) {
$ordered_ret[$c] .= "|".$data;
}
$ordered_ret[$c] .= "\n";
}
$textbox->Append($_) for @ordered_ret;
}
}
sub compute {
my ($begin, $end) = (shift, shift);
my (@tbl, $cpt);
for ($cpt = $begin; $cpt < $end; $cpt++) {
push @tbl, $cpt;
}
return @tbl;
}
Regards, Mario
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.