is Win32::GUI thread safe?

T

Tom F.

I've been working on a script for a little while now
It's a program that will periodically log me into my campus's content
filtering device (Barracuda). Of course, it makes sense to implement
some sort of timeout handling, just in case I lose the net connection or
happen to have my laptop somewhere else.

Here's the problem: the script keeps crashing with the following message:

Free to wrong pool 3d9b108 not 1981c78 at C:/Perl/site/lib/Win32/GUI.pm
line 3480 during global destruction.

the crazy thing is, no GUI element is changed during the spot where I
split into threads and then re-join into one. through the use of print
statements, I've narrowed it down to the statement where I join a thread.

(2 threads: 1 timer, 1 do-er; if the timer is ready but the do-er isn't,
then kill it)

and it happens no matter which thread is joined!

I've tested all the net stuff without the GUI (but using threads) and it
works fine. So, that leads me to think Win32::GUI is not thread safe,
and the mere presence of any of the different GUI objects is causing my
problem.

Google has only revealed very old information and other dead ends. Help!
 
Z

zentara

I've tested all the net stuff without the GUI (but using threads) and it
works fine. So, that leads me to think Win32::GUI is not thread safe,
and the mere presence of any of the different GUI objects is causing my
problem.

Google has only revealed very old information and other dead ends. Help!

Perl/Tk is the same way...not thread safe. It can still be used with
threads with precautions, google for "perl tk threads" for examples.

I would bet that you can solve the problem by :

1. Create the thread first in the program, before any gui code is
invoked. For instance, you cannot reliably launch threads from
a gui callback. Threads get a copy of the parent when spawned,
so you want to spawn early before gui code statements are used.

2. Never try to access gui widgets from a thread, use shared variables
to communicate back to the main thread, and manipulate the widgets
from the main thread.

zentara
 
T

Tom F.

zentara said:
Perl/Tk is the same way...not thread safe. It can still be used with
threads with precautions, google for "perl tk threads" for examples.

I would bet that you can solve the problem by :

1. Create the thread first in the program, before any gui code is
invoked. For instance, you cannot reliably launch threads from
a gui callback. Threads get a copy of the parent when spawned,
so you want to spawn early before gui code statements are used.

Is there any way to tell perl or the threads module not to make that
copy? I saw something like this:

sub Win32::GUI::CLONE_SKIP {1};

that would stop the copy, but I'm not sure it was working when I tried
to use it, though I wasn't sure if I had absolutely covered all the
different non thread-safe modules that were being used inside these
(i.e., Win32::GUI::Window might use non-thread-safe Win32::foo::bar
internally)
2. Never try to access gui widgets from a thread, use shared variables
to communicate back to the main thread, and manipulate the widgets
from the main thread.

I knew about that, and was/am avoiding it.

Do you think trying to use the GUI elements as shared variables would
solve it (does sharing simply synchronize the copies or does it stop the
copying?)
 
T

Tom F.

zentara said:
Perl/Tk is the same way...not thread safe. It can still be used with
threads with precautions, google for "perl tk threads" for examples.

I would bet that you can solve the problem by :

1. Create the thread first in the program, before any gui code is
invoked. For instance, you cannot reliably launch threads from
a gui callback. Threads get a copy of the parent when spawned,
so you want to spawn early before gui code statements are used.

Is there any way to tell perl or the threads module not to make that
copy? I saw something like this:

sub Win32::GUI::CLONE_SKIP {1};

that would stop the copy, but I'm not sure it was working when I tried
to use it, though I wasn't sure if I had absolutely covered all the
different non thread-safe modules that were being used inside these
(i.e., Win32::GUI::Window might use non-thread-safe Win32::foo::bar
internally)
2. Never try to access gui widgets from a thread, use shared variables
to communicate back to the main thread, and manipulate the widgets
from the main thread.

I knew about that, and was/am avoiding it.

Do you think trying to use the GUI elements as shared variables would
solve it (does sharing simply synchronize the copies or does it stop the
copying?)

~~ Tom
 
Z

zentara

zentara wrote:

Is there any way to tell perl or the threads module not to make that
copy? I saw something like this:

sub Win32::GUI::CLONE_SKIP {1};

that would stop the copy, but I'm not sure it was working when I tried
to use it, though I wasn't sure if I had absolutely covered all the
different non thread-safe modules that were being used inside these
(i.e., Win32::GUI::Window might use non-thread-safe Win32::foo::bar
internally)

I don't use win32, so use a grain of salt with this.
Did CLONE_SKIP seem to work? Also test 10 or 20 runs. Threads will
act funny sometimes, seeming to run fine, then crashing unexpectedly
after 20 tests.

Gtk2 has a thread safety mechanism similar to the CLONE_SKIP you
mention, it's called set_threadsafe. BUT it is at the lowest level of
Glib, which the Gtk2 gui code is based on; so in theory it accounts for
all objects. One thing though, Glib::Object->set_threadsafe(1) must
be the first statement in the script.
So maybe make sure CLONE_SKIP is the first line in your script.
Also I'm not an expert at this, but I believe these thread safety
mechanisms only affect the ref_count of the objects.....in reality,
the spawned threads get an exact copy of the parent at the time of
creation...... the gui code in the spawned thread may be disabled, but
it still gets copied due to the way threads get spawned. I may be wrong,
I seldom delve that deep and prefer just to work around it with the
hacks that I've mentioned.
Do you think trying to use the GUI elements as shared variables would
solve it (does sharing simply synchronize the copies or does it stop the
copying?)

You don't share the GUI widgets as shared variables, Perl only allows
scalars in shared vars. In Gtk2 ,you can pass in a widget reference in
the threads->new(\&codeblock, $somewidget), and then access the widget
by a Glib->Idle_add() statement. Does Win32::Gui have something like
Idle_add? Adds a callback at first idle moment in the event loop.

What I meant about shared vars was try to keep only non-gui code in the
threads, and use timers in the parent thread to read shared vars set in
the thread. Then the timer can manipulate the gui widget with that data.
You need a timer in the parent thread constantly reading the shared
variables, because they are NOT automatically updated in the parent
thread, when a child thread sets them.
The only exception to this, is shared filehandles, which the parent can
read as it comes in.

For deeper expertise, you might want to ask on http://perlmonks.org

Hope that helps,
zentara
 
T

Tom F.

You don't share the GUI widgets as shared variables, Perl only allows
scalars in shared vars. In Gtk2 ,you can pass in a widget reference in
the threads->new(\&codeblock, $somewidget), and then access the widget
by a Glib->Idle_add() statement. Does Win32::Gui have something like
Idle_add? Adds a callback at first idle moment in the event loop.

Thanks, I think I am just going to have to use shared variables as flags and
whatnot. Dang, I had this thing written 5 times over if only it was friggin'
thread safe.
 
R

Robert May


Correct. Each object gets cloned in the thread, and when the thread
terminates the DESTORY() method is called for each object during perl
global clean-up. For many of the objects calling the DESTROY() method
from anything other than the thread that created the object is a no-
no.

Take a look at Win32::GUI::ThreadUtils here:
http://www.robmay.me.uk/win32gui (towards the bottom of the page.

This should work - and IIRC was the recommended way for some time. It
relies on you knowning how many thread you'll need before creating any
GUI objects.
Is there any way to tell perl or the threads module not to make that
copy? I saw something like this:

sub Win32::GUI::CLONE_SKIP {1};

That's pretty much what Win32::GUI::ThreadUtils does (both for all the
relevant Win32::GUI::* classes). There's also some code to easy inter-
thread communications, but you can ignore that if you don't need it.
that would stop the copy, but I'm not sure it was working when I tried
to use it, though I wasn't sure if I had absolutely covered all the
different non thread-safe modules that were being used inside these
(i.e., Win32::GUI::Window might use non-thread-safe Win32::foo::bar
internally)

Win32::GUI::ThreadUtils should cover all the necessary classes -
unless you are using any GUI classes that are not distributed in the
Win32::GUI package.
I knew about that, and was/am avoiding it.

Do you think trying to use the GUI elements as shared variables would
solve it (does sharing simply synchronize the copies or does it stop the
copying?)

I haven't looked recently, but until very recent threads.pm it wasn't
possible to share blessed objects. This might work, although it is
important to ensure that the thread that creates the GUI objects
finishes last, so that it is the one that ends up calling DESTROY().

Hope this help,
Rob.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top