Threads breaking either Perl's or Gtk2's internals



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;





[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]