|
Fine, thanks for such a prompt reply! I'll have a look at your code now. I'm already proceeding with a similar scheme, where all worker threads are created before any Gtk stuff and instructed via queues to eval strings (the code in not known in advance). I was just hoping that perhaps the development leaped ahead. :) Btw, earlier I found one of your scripts with a similar approach (attached as thr.pl), but that also gives me a nasty error on exit: dave jeeves:~$ perl thr.pl GLib-GObject-WARNING **: instance of invalid non-instantiatable type `<invalid>'. GLib-GObject-CRITICAL **: g_signal_emit_valist: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed. GLib-GObject-WARNING **: instance of invalid non-instantiatable type `<invalid>'. GLib-GObject-CRITICAL **: g_signal_handlers_destroy: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed. GLib-GObject-WARNING **: instance of invalid non-instantiatable type `<invalid>'. GLib-GObject-CRITICAL **: g_signal_handlers_destroy: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed. GLib-GObject-WARNING **: instance of invalid non-instantiatable type `<invalid>'. GLib-GObject-CRITICAL **: g_signal_emit_valist: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed. GLib-GObject-WARNING **: instance of invalid non-instantiatable type `<invalid>'. GLib-GObject-CRITICAL **: g_signal_handlers_destroy: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed. GLib-GObject-WARNING **: instance of invalid non-instantiatable type `<invalid>'. GLib-GObject-CRITICAL **: g_signal_handlers_destroy: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed. GLib-GObject-CRITICAL **: g_object_unref: assertion `G_IS_OBJECT (object)' failed. GLib-GObject-WARNING **: instance of invalid non-instantiatable type `(null)'. GLib-GObject-CRITICAL **: g_signal_emit_valist: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed. GLib-GObject-WARNING **: instance of invalid non-instantiatable type `(null)'. GLib-GObject-CRITICAL **: g_signal_handlers_destroy: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed. GLib-GObject-WARNING **: instance of invalid non-instantiatable type `(null)'. GLib-GObject-CRITICAL **: g_signal_handlers_destroy: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed. Segmentation fault A bit unsettling as you create the thread before Gtk2->main, which seems to be considered quite safe. :) The only threaded script I found working 100% so far is thread_usage.pl from some Gtk2-perl tutorial. Interesting is that it seems to create threads at the same point like you (after Gtk2 widget stuff, before Gtk2->main) and it works. It even touches the GUI from other threads. All this makes me a bit nervous about Gtk-perl. Looks like a lot of depends on "unrelated" conditions. My app is gonna have a lot of IPC and threads and I'm seriously thinking about moving to good old Gtk/C, which would mean MUCH more code, time, testing... :( -- David Kubíček System Specialist T-Systems Czech Republic a.s. Na Karmeli 1457 Mladá Boleslav 29301, Czech Republic Mobile: (+420) 739 242 055 Phone: (+420) 236 099 459 PGP: http://awk.cz/key.pgp http://awk.cz/key.pem Email: kubicek gedas cz david kubicek t-systems com kubicek awk cz Connection to localhost closed by remote host. zentara wrote: On Mon, 24 Mar 2008 14:47:05 +0100 David Kubíček <dave awk cz> wrote: |
#!/usr/bin/perl
use warnings;
use strict;
use threads;
use threads::shared;
use Glib qw/TRUE FALSE/;
use Gtk2 qw/-init -threads-init/;
#setup shared hash
my %shash;
share(%shash); #will work for first level keys
$shash{'go'} = 0;
$shash{'work'} = '';
$shash{'die'} = 0;
my $window = Gtk2::Window->new('toplevel');
$window ->signal_connect( 'destroy' => \&delete_event );
$window->set_border_width(10);
$window->set_size_request(300,300);
my $vbox = Gtk2::VBox->new( FALSE, 6 );
$window->add($vbox);
$vbox->set_border_width(2);
my $hbox= Gtk2::HBox->new( FALSE, 6 );
my $hbox1 = Gtk2::HBox->new( FALSE, 6 );
$vbox->pack_end($hbox,FALSE,FALSE,0);
$vbox->pack_end (Gtk2::HSeparator->new, FALSE, FALSE, 0);
$vbox->pack_end($hbox1,FALSE,FALSE,0);
$hbox->set_border_width(2);
$vbox->pack_end (Gtk2::HSeparator->new, FALSE, FALSE, 0);
my $ebutton = Gtk2::Button->new_from_stock('gtk-quit');
$hbox->pack_end( $ebutton, FALSE, FALSE, 0 );
$ebutton->signal_connect( clicked => \&delete_event );
my $pbar = Gtk2::ProgressBar->new();
$pbar->set_pulse_step(.1);
$hbox->pack_start($pbar,1,1,0);
my $count = 0;
my $label_w_markup = Gtk2::Label->new();
$label_w_markup->set_markup("<span foreground=\"yellow1\"
size=\"40000\">$count</span>");
$vbox->pack_end($label_w_markup,FALSE,FALSE,4);
my $tbutton = Gtk2::Button->new_with_label('Run Thread');
$hbox1->pack_start($tbutton , 1, 1, 0 );
my $lconnect = $tbutton->signal_connect( clicked => sub{ launch() });
my $sconnect;
$window->show_all();
$pbar->hide; #needs to be called after show_all
#create 1 sleeping thread passing it the label and pbar to control
my $thread = threads->new(\&work, $label_w_markup, $pbar);
Gtk2->main;
######################################
sub delete_event {
$shash{'go'} = 0;
$shash{'die'} = 1;
$thread->join;
Gtk2->main_quit;
return FALSE;
}
#######################################
sub launch{
$pbar->show;
$tbutton->set_label('Stop Thread');
$tbutton->signal_handler_block($lconnect);
$sconnect = $tbutton->signal_connect( clicked => sub{ stop() });
$shash{'go'} = 1;
}
##################################################
sub stop{
print "stopped\n";
$shash{'go'} = 0;
$pbar->hide;
$tbutton->set_label('Run Thread');
$tbutton->signal_handler_block ($sconnect);
$tbutton->signal_handler_unblock ($lconnect);
}
#########################################################
sub work{
my ($label,$pbar) = @_;
$|++;
while(1){
if($shash{'die'} == 1){ goto END };
if ( $shash{'go'} == 1 ){
foreach my $num (1..1000){
Glib::Idle->add(
sub{
if($shash{'die'} == 1){ return };
$label->set_markup("<span foreground=\"yellow1\"
size=\"40000\">$num</span>");
$pbar->pulse;
return FALSE;
});
select(undef,undef,undef, .1);
if($shash{'go'} == 0){last}
if($shash{'die'} == 1){ goto END };
}
$shash{'go'} = 0; #turn off self before returning
}else
{ select(undef,undef,undef,.1) } #sleep time
}
END:
}
#!/usr/bin/perl
#
# $Header: /cvsroot/gtk2-perl/gtk2-perl-xs/Gtk2/examples/thread_usage.pl,v 1.4 2004/06/23 01:00:15 rwmcfa1
Exp $
#
# -rm
#
use strict;
use warnings;
use Data::Dumper;
use Glib qw(TRUE FALSE);
use Gtk2 qw/-init -threads-init 1.050/;
die "Glib::Object thread safetly failed"
unless Glib::Object->set_threadsafe (TRUE);
my $win = Gtk2::Window->new;
$win->signal_connect (destroy => sub { Gtk2->main_quit; });
$win->set_title ($0);
$win->set_border_width (6);
$win->set_default_size (640, 480);
my $hbox = Gtk2::HBox->new (FALSE, 6);
$win->add ($hbox);
my $vbox = Gtk2::VBox->new (FALSE, 6);
$hbox->pack_start ($vbox, FALSE, FALSE, 0);
my $worklog = Log->new;
$hbox->pack_start ($worklog, TRUE, TRUE, 0);
my @workers;
my $worker;
foreach (1..5)
{
$worker = Worker->new ($worklog);
$vbox->pack_start ($worker, FALSE, FALSE, 0);
$worker->set_worker_label ('Worker '.$_);
push @workers, $worker;
}
my $pending = Gtk2::Label->new ('0 jobs pending');
$vbox->pack_start ($pending, FALSE, FALSE, 0);
Glib::Timeout->add (500, sub {
$pending->set_text (Worker->jobs_pending.' jobs pending');
1;
});
my $count = 0;
my $go = Gtk2::Button->new ('_Go');
$vbox->pack_start ($go, FALSE, FALSE, 0);
$go->signal_connect (clicked => sub {
foreach (@workers)
{
Worker->do_job ($count + rand);
$count++;
}
});
my $quit = Gtk2::Button->new_from_stock ('gtk-quit');
$vbox->pack_start ($quit, FALSE, FALSE, 0);
$quit->signal_connect (clicked => sub {
$go->set_sensitive (FALSE);
$quit->set_sensitive (FALSE);
Worker->all_fired;
Gtk2->main_quit;
});
$win->show_all;
Gtk2->main;
package Worker;
use strict;
use warnings;
use Data::Dumper;
use threads;
use threads::shared;
use Thread::Queue;
use Glib qw(TRUE FALSE);
use base 'Gtk2::HBox';
our $_nworkers : shared = 0;
my $_jobs;
BEGIN
{
$_jobs = Thread::Queue->new;
}
sub do_job
{
shift; # class
$_jobs->enqueue (shift);
}
sub all_fired
{
shift; # class
# put on a quit command for each worker
foreach (1..$_nworkers)
{
$_jobs->enqueue (undef);
}
while ($_nworkers)
{
Gtk2->main_iteration;
}
}
sub jobs_pending
{
return $_jobs->pending;
}
sub new
{
my $class = shift;
my $worklog = shift;
my $self = Gtk2::HBox->new (FALSE, 6);
# rebless to a worker
bless $self, $class;
# gui section
my $label = Gtk2::Label->new ('Worker:');
$self->pack_start ($label, FALSE, FALSE, 0);
my $progress = Gtk2::ProgressBar->new;
$self->pack_start ($progress, FALSE, FALSE, 0);
$progress->set_text ('Idle');
$self->{label} = $label;
$self->{progress} = $progress;
$self->{worklog} = $worklog;
# thread section
$self->{child} = threads->new (\&_worker_thread, $self);
$_nworkers++;
return $self;
}
sub set_worker_label
{
my $self = shift;
my $name = shift;
$self->{label}->set_text ($name);
}
sub _worker_thread
{
my $self = shift;
my $progress = $self->{progress};
my $worklog = $self->{worklog};
my $i;
my $job;
my $sleep;
# undef job means quit
while (defined ($job = $_jobs->dequeue))
{
$worklog->insert_msg ($self->{label}->get_text
." is doing job ($job)\n");
if (rand > 0.5)
{
$sleep = 1 + rand;
}
else
{
$sleep = 1 - rand;
}
for ($i = 0; $i < 1.1; $i += 0.25)
{
Gtk2::Gdk::Threads->enter;
$progress->set_fraction ($i);
$progress->set_text ($i * 100 .'%');
Gtk2::Gdk::Threads->leave;
# we're state employee's, so let's do some 'work'...
sleep $sleep;
}
$worklog->insert_msg ($self->{label}->get_text
." done with job ($job)\n");
}
$_nworkers--;
}
package Log;
use strict;
use warnings;
use Glib qw(TRUE FALSE);
use base 'Gtk2::ScrolledWindow';
sub new
{
my $class = shift;
my $self = Gtk2::ScrolledWindow->new;
my $buffer = Gtk2::TextBuffer->new;
my $view = Gtk2::TextView->new_with_buffer ($buffer);
$self->add ($view);
$view->set (editable => FALSE, cursor_visible => FALSE);
$self->{view} = $view;
$self->{buffer} = $buffer;
bless $self, $class;
$self->insert_msg ("Start...\n-------------------------------------\n");
return $self;
}
sub insert_msg
{
my $self = shift;
my $msg = shift;
my $buffer = $self->{buffer};
Gtk2::Gdk::Threads->enter;
my $iter = $buffer->get_end_iter;
$buffer->insert ($iter, $msg);
$iter = $buffer->get_end_iter;
$self->{view}->scroll_to_iter ($iter, 0.0, FALSE, 0.0, 0.0);
Gtk2::Gdk::Threads->leave;
}
Attachment:
signature.asc
Description: OpenPGP digital signature