is Win32::GUI thread safe?

Discussion in 'Perl Misc' started by Tom F., Oct 3, 2008.

  1. Tom F.

    Tom F. Guest

    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!
    Tom F., Oct 3, 2008
    #1
    1. Advertising

  2. Tom F.

    zentara Guest

    On Thu, 02 Oct 2008 23:36:16 -0400, "Tom F."
    <> wrote:
    >
    >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


    --
    I'm not really a human, but I play one on earth.
    http://zentara.net/Remember_How_Lucky_You_Are.html
    zentara, Oct 3, 2008
    #2
    1. Advertising

  3. Tom F.

    Tom F. Guest

    zentara wrote:
    > On Thu, 02 Oct 2008 23:36:16 -0400, "Tom F."
    > <> wrote:
    >> 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.


    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?)

    > zentara
    >
    >
    Tom F., Oct 3, 2008
    #3
  4. Tom F.

    Tom F. Guest

    zentara wrote:
    > On Thu, 02 Oct 2008 23:36:16 -0400, "Tom F."
    > <> wrote:
    >> 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.


    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
    Tom F., Oct 3, 2008
    #4
  5. Tom F.

    zentara Guest

    On Fri, 03 Oct 2008 14:34:48 -0400, "Tom F."
    <> wrote:

    >zentara wrote:


    >> 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)


    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


    --
    I'm not really a human, but I play one on earth.
    http://zentara.net/Remember_How_Lucky_You_Are.html
    zentara, Oct 4, 2008
    #5
  6. Tom F.

    Tom F. Guest

    zentara wrote:
    >> zentara wrote:

    >
    >>> 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.


    > 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.
    Tom F., Oct 5, 2008
    #6
  7. Tom F.

    Robert May Guest

    On Oct 3, 7:34 pm, "Tom F." <> wrote:
    > zentara wrote:
    > > On Thu, 02 Oct 2008 23:36:16 -0400, "Tom F."
    > > <> wrote:
    > >> 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,


    Correct.

    > >> and the mere presence of any of the different GUI objects is causing myhttp://groups.google.com/group/comp.lang.perl.misc/browse_frm/thread/36c709fb2699584a#
    > >> problem.


    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.

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


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

    > > 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.


    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.

    > > 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?)


    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.
    Robert May, Oct 5, 2008
    #7
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Lialie - KingMax
    Replies:
    1
    Views:
    288
    John Henry
    Dec 15, 2006
  2. Gabriel Rossetti
    Replies:
    0
    Views:
    1,297
    Gabriel Rossetti
    Aug 29, 2008
  3. Replies:
    1
    Views:
    326
    Brian Candler
    Aug 12, 2003
  4. Vincenzo Piombo
    Replies:
    1
    Views:
    152
  5. John Nagle
    Replies:
    5
    Views:
    453
    John Nagle
    Mar 12, 2012
Loading...

Share This Page