Hello, I'm having problems with threads in my GTK application. You can see exactly what I'm doing from the attached files. Both were originally a testing script I found here when browsing archives, so please ignore formatting, etc - they're not mine. :) I only changed the threading "management". The problem is that I can't seem to find a safe method of spawning worker threads. The examples are _almost_ perfect, but breaking down after several create/join cycles even though I use all the init work I found currently being described as "working" (set_threadsafe, -threads-init). Gtk is touched only from the main thread, no stunts... I found somebody having a very similar problem, but his report was refused as NOTABUG. They say that moving Glib thread safety initialization before any Gtk2 stuff solves it, but that's not true. Not even before "use Gtk2". The threading problems are still there. :( URL: http://www.nabble.com/-Gtk2-perl-bugs---Bug-507610--New%3A-gtk2-perl-unthreads-safe-td14643859.html I'm using Debian unstable: libgtk2.0-0 ~ 2.12.9-2 libgtk2-gladexml-perl ~ 1.006-1 libgtk2-perl ~ 1:1.161-1 The version ThreadDemo3.pl has $buttonStart "clicked" signal handler in a named sub, ThreadDemo4.pl uses the same routine, but as anonymous sub. One would think there couldn't be any difference, but there are - quite big actually. Obviously, one shuffles Gtk's internals and the other suffles Perl's. NOTE: Please ignore non-responsiveness of GUI, I raised the select() delay on purpose to shrink debugging output - it can be made responsive with values < 0.3. Also, I'd prefer the recursive Gtk loop (Gtk2->main_iteration) in the signal handler. I know I could do it using Timeouts, but that doesn't fit my real application and also doesn't help with the actual threading problems. ThreadDemo3.pl breaks after several (usually 3-4) clicks on the "start" button (after waiting for each cycle to finish) with the following output: dave jeeves:~$ perl ThreadDemo3.pl Waiting for thread QUEUE notify Waiting for thread QUEUE notify Waiting for thread QUEUE notify JOINING JOINED Waiting for thread QUEUE notify Waiting for thread QUEUE notify Waiting for thread QUEUE notify JOINING JOINED Waiting for thread QUEUE notify Waiting for thread QUEUE notify Waiting for thread QUEUE notify JOINING JOINED Waiting for thread QUEUE notify Waiting for thread QUEUE notify Waiting for thread QUEUE notify JOINING JOINED GLib-GObject-CRITICAL **: g_object_unref: assertion `G_IS_OBJECT (object)' failed at ThreadDemo3.pl line 30. GLib-GObject-WARNING **: instance of invalid non-instantiatable type `(null)' at ThreadDemo3.pl line 30. GLib-GObject-CRITICAL **: g_signal_emit_valist: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed at ThreadDemo3.pl line 30. GLib-GObject-WARNING **: instance of invalid non-instantiatable type `(null)' at ThreadDemo3.pl line 30. GLib-GObject-CRITICAL **: g_signal_handlers_destroy: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed at ThreadDemo3.pl line 30. GLib-GObject-WARNING **: instance of invalid non-instantiatable type `(null)' at ThreadDemo3.pl line 30. GLib-GObject-CRITICAL **: g_signal_handlers_destroy: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed at ThreadDemo3.pl line 30. ThreadDemo4.pl has a different problem (manifests after clicking "start" twice or more, plus every time the app exits even after just one cycle): dave jeeves:~$ perl ThreadDemo4.pl Waiting for thread QUEUE notify Waiting for thread QUEUE notify Waiting for thread QUEUE notify JOINING JOINED Attempt to free unreferenced scalar: SV 0x85fb078, Perl interpreter: 0x8150008 at ThreadDemo4.pl line 61. >From that, I can see it doesn't break inside join(), but somewhere in the main Gtk loop (Gtk2->main). -- 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. |
#!/usr/bin/perl use warnings; use strict; use threads; use threads::shared; use Glib qw(TRUE FALSE); # To get TRUE and FALSE Glib::Object->set_threadsafe (TRUE); use Gtk2 qw(-threads-init -init); my @queue:shared; # Create the window my $window = Gtk2::Window->new('toplevel'); my $box = Gtk2::VBox->new; my $pbar = Gtk2::ProgressBar->new; my $buttonQuit = Gtk2::Button->new('Quit'); my $buttonStart = Gtk2::Button->new('Start'); $window->add ($box); $box->add ($pbar); $box->add($buttonQuit); $box->add($buttonStart); $buttonQuit->signal_connect(clicked => sub{Gtk2->main_quit}); $buttonStart->signal_connect(clicked => \&signal); $window->show_all; Gtk2->main; exit; sub signal { my $thread = threads->new(sub { my $n = 2; for (my $i = 0; $i <= $n; $i++) { sleep(1); lock @queue; push @queue, $i/$n; push @queue, "Running $i of $n"; } }); while ( 1 ) { if (@queue) { print "QUEUE notify\n"; my $fraction = shift @queue; my $text = shift @queue; $pbar->set_fraction($fraction); $pbar->set_text($text); if ($fraction == 1) { print "JOINING\n"; $thread->join; print "JOINED\n"; last; } } print "Waiting for thread\n"; select(undef, undef, undef, 1.5); Gtk2->main_iteration while Gtk2->events_pending; } }
#!/usr/bin/perl use warnings; use strict; use threads; use threads::shared; use Glib qw(TRUE FALSE); # To get TRUE and FALSE Glib::Object->set_threadsafe (TRUE); use Gtk2 qw(-threads-init -init); my @queue:shared; # Create the window my $window = Gtk2::Window->new('toplevel'); my $box = Gtk2::VBox->new; my $pbar = Gtk2::ProgressBar->new; my $buttonQuit = Gtk2::Button->new('Quit'); my $buttonStart = Gtk2::Button->new('Start'); $window->add ($box); $box->add ($pbar); $box->add($buttonQuit); $box->add($buttonStart); $buttonQuit->signal_connect(clicked => sub{Gtk2->main_quit}); $buttonStart->signal_connect(clicked => sub { my $thread = threads->new(sub { my $n = 2; for (my $i = 0; $i <= $n; $i++) { sleep(1); lock @queue; push @queue, $i/$n; push @queue, "Running $i of $n"; } }); while ( 1 ) { if (@queue) { print "QUEUE notify\n"; my $fraction = shift @queue; my $text = shift @queue; $pbar->set_fraction($fraction); $pbar->set_text($text); if ($fraction == 1) { print "JOINING\n"; $thread->join; print "JOINED\n"; last; } } print "Waiting for thread\n"; select(undef, undef, undef, 1.5); Gtk2->main_iteration while Gtk2->events_pending; } }); $window->show_all; Gtk2->main; exit;