Re: Threads breaking either Perl's or Gtk2's internals



On Mon, 2008-03-24 at 14:47 +0100, David KubÃÄek wrote:

I'm having problems with threads in my GTK application.

All this should really just work.  So I started looking into it.
Tonight is now the fourth night in a row that I've been trying to fix
this, and I still don't have a solution that works in every case.

When you create a thread via threads->new, perl clones everythingïï
(subs, variables)ï that is not marked as "shared" from the current
thread.  So normally, both threads see independent copies of all the
variables and subs.  It does this automatically for all the normal Perl
stuff, but it can't do it for magic variables that are associated with
underlying C objects.

So perl provides a hook for these cases: when you define a CLONE method,
it is called in the context of the new thread whenever one is created.
Unfortunately, the CLONE method is called only with the package name and
only once per package.  So in order to clone our GObject wrappers, we
need to keep a table of all the objects we ever encountered.

Now the idea is that CLONE just increments the reference count of every
object.  When the thread exits, the cloned variables go out of scope and
the references are released again.  This is what the current
thread-safety code in Glib::Object does.

This works as long as there's a one-to-one mapping from C things to Perl
variables.  That's not the case for Glib::Object, though.  When you have
a signal handler for a button's clicked signal, the signal handler's
first argument and the button variable from the outer scope are
different Perl variables but they wrap the same C pointer.  I think this
is what breaks your demo programs: when the thread is created, both of
those variables are cloned, but we only increment the reference count of
the GObject once; when the thread exits, both variables go out of scope
and the reference count is decremented twice.

My idea of fixing this was to count the number of Perl wrappers we hand
out for each GObject and in CLONE increment the reference count as many
times as there are wrappers.  This didn't seem to work properly:
sometimes the programs still crashed, mostly there were leaks though.

Another idea was to store a variable=>GObject mapping in the table I
mentioned earlier and iterate this table in CLONE, referencing every
GObject once.  Since different variables might point to the same
GObject, this amounts to increasing the reference count of some GObjects
more than once.  In retrospect, this should be exactly the same as the
first approach -- but for some reason, this one worked a little better.
A corresponding patch to Glib is attached.

It's still not working correctly in every case, though.  The attached
program works fine for example, but if you enable the commented out
inner thread stuff, it breaks.

So, does anyone know how to get this going correctly?

For reference, here's some useful information I found:

â `perldoc perlmod' has a section about "Making your module threadsafe",
mentioning CLONE and CLONE_SKIP.

â `perldoc perlguts' has some general information about multiple threads
and perl in "How multiple interpreters and concurrency are supported".

ïâ <http://www.perlmonks.org/?node_id=483162> has a supposedly working
Perl implementation of the CLONE stuff for inside-out objects.

ïïâ In the thread
<http://www.mail-archive.com/dev perl apache org/msg09877.html>, Stas
Bekman talks about making mod_perl 2 thread-safe.  He even created an
example module demonstrating a supposedly working approach for an XS
module that wraps the C objects.  His C objects are only ever referenced
by one variable, though.  I have yet to try his approach of using a perl
HV to store the mapping though.

ïïïâ Once this all works on the Perl side, Andrew Cowie tells you to
handle gtk+ itself when using multiple threads:
<http://research.operationaldynamics.com/blogs/andrew/software/gnome-desktop/gtk-thread-awareness.html>

-- 
Bye,
-Torsten

Attachment: thread-safety.patch
Description: Text Data

Attachment: thread-demo.pl
Description: Perl program



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