Threaded Gtk2->main causing seg fault
- From: Kevin Leung <xhidem yahoo com hk>
- To: gtk-perl-list gnome org
- Subject: Threaded Gtk2->main causing seg fault
- Date: Thu, 22 Apr 2004 06:02:28 +0800
Hi
I understand that this is not normal usage of perl gtk+, but I really
have no options because I am writing a plugin which must provide a GUI.
If I just run the Gtk2->main without a new thread, the plugin will block.
My system config:
Freebsd-stable
gtk+-2.4.0
perl-5.8.2
p5-Gtk2-1.040
What I did was:
In main:
1. create a instance of some object, namely $base (which has signal)
2. create a thread.
In the thread:
1. create the widgets.
2. connect the Gtk2->main_quit to window's destroy signal.
3. connect $base 's signal.
4. run Gtk2->main.
Back in main:
1. sleep for awhile.
2. make $base emit a signal.
3. make the thread->join
The seg fault comes when I tried to close the window. It gives alot of
warnings about wrong reference counts. I rewrite the same thing in C
just to make sure gtk allows gtk_main in new thread, and the C version
runs fine.
The warnings are as followed:
in callbackUnbalanced string table refcount: (2) for "::ISA::CACHE::"
during global destruction.
Unbalanced string table refcount: (1) for "signal_connect" during global
destruction.
Unbalanced string table refcount: (1) for "add" during global destruction.
Unbalanced string table refcount: (2) for "DESTROY" during global
destruction.
Unbalanced string table refcount: (1) for "show_all" during global
destruction.
The C and perl version of the code are attached. Any one interested may
try running them.
Kevin Leung
use strict;
use warnings;
package Base;
use Gtk2;
use Glib::Object::Subclass
'Glib::Object',
signals => {
'refresh' => {}
},
properties => [
Glib::ParamSpec->boxed (
'servers',
'servers',
'Hash of servers',
'Glib::Scalar',
[qw/readable writable/]),
]
;
sub INIT_INSTANCE
{
my $self = shift;
$self->{servers} = {};
}
package main;
use Gtk2 '-init';
use threads;
use threads::shared;
my $base = Base->new ();
share ($base);
my $thr = threads->new (\&run);
sub run
{
my $win;
my $label;
$win = Gtk2::Window->new ();
$label = Gtk2::Label->new ('NULL');
$win->add ($label);
lock ($base);
$base->signal_connect ('refresh', \&refresh_cb, $label);
$win->signal_connect ('destroy', sub {
Gtk2->main_quit;
});
$win->show_all ();
Gtk2->main ();
}
sub refresh_cb
{
my ($self, $label) = @_;
$label->set_text ('IN CALLBACK');
print 'in callback';
}
sleep 1;
$base->signal_emit ('refresh');
$thr->join ();
#include <stdio.h>
#include <unistd.h>
#include <gtk/gtk.h>
#include <pthread.h>
/* Define a new Object here */
typedef struct _Base Base;
typedef struct _BaseClass BaseClass;
#define TYPE_BASE (base_get_type ())
struct _Base {
GObject parent;
};
struct _BaseClass {
GObjectClass parent_class;
void (*refresh) (void *);
};
enum {
REFRESH,
TOTAL
};
static void base_class_init (BaseClass *klass);
static void base_init (Base *base);
static void base_finalize (GObject *object);
static GObjectClass *parent_class = NULL;
static guint signals[TOTAL];
static Base *base = NULL;
GType base_get_type (void)
{
static GType type = 0;
if (!type) {
static const GTypeInfo info = {
sizeof (BaseClass),
NULL, NULL,
(GClassInitFunc) base_class_init,
NULL, NULL,
sizeof (Base),
0,
(GInstanceInitFunc) base_init,
0
};
type = g_type_register_static (G_TYPE_OBJECT, "Base", &info, 0);
}
return type;
}
static void base_class_init (BaseClass *klass)
{
GObjectClass *obj_class = (GObjectClass *) klass;
obj_class->finalize = base_finalize;
parent_class = g_type_class_peek_parent (klass);
signals[REFRESH] = g_signal_new (
"refresh",
TYPE_BASE,
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (BaseClass, refresh),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
}
static void base_init (Base *base)
{
}
static void base_finalize (GObject *object)
{
parent_class->finalize (object);
}
static void base_emit (Base *base, gpointer ptr)
{
g_signal_emit (base, signals[REFRESH], 0, ptr);
}
static Base* base_new (void)
{
Base *base = g_object_new (TYPE_BASE, NULL);
return base;
}
/* Using the Object */
static void* start_gtk (void *);
int main (int argc, char **argv)
{
gtk_init (&argc, &argv);
pthread_t thread;
base = base_new ();
if (pthread_create (&thread, NULL, start_gtk, NULL)) {
printf ("Error pthread_create\n");
return 1;
}
sleep (3);
base_emit (base, NULL);
pthread_join (thread, NULL);
return 0;
}
static void refresh_cb (Base *base, gpointer ptr)
{
printf ("Refreshed\n");
}
static void* start_gtk (void *data)
{
GtkWidget *win;
GtkWidget *label;
win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
label = gtk_label_new ("NULL");
gtk_container_add (GTK_CONTAINER (win), label);
g_signal_connect (G_OBJECT (win), "destroy",
G_CALLBACK (gtk_main_quit), NULL);
g_signal_connect (G_OBJECT (base), "refresh",
G_CALLBACK (refresh_cb), NULL);
gtk_widget_show_all (win);
gtk_main ();
return NULL;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]