Ace128 has asked for the wisdom of the Perl Monks concerning the following question:

Hey Monks,

Ok, I have tested and tested and tested, trying to make this work, but no luck. I've managed to shorten the quite large and complex applictaion to the following lines:
use Tk; use Tk::MatchEntry; use threads; #use Time::HiRes qw( usleep ); use Data::Dumper; use strict; use warnings; my $mw = MainWindow->new(-title => "MatchEntry Test"); my @choices = ( ["01234", "345345", "64364"], ["abcsdf", "3waaxx", "6azz4"], ["aaac4", "aaaaabbbbbbbbb", "aaaaaadddddd"] ); #print Dumper(@choices); my $full_PathMatchEntry = $mw->MatchEntry ( -width => 10, -choices => \@choices, -autopopup => 0, -complete => 1, -ignorecase => 1, -maxheight => 15, -background => "#FFFFFF" )->pack(-fill => 'x', -expand => 1, -side +=> 'left'); threads->create('searchUpdate', \$full_PathMatchEntry); $full_PathMatchEntry->focus; $full_PathMatchEntry->bind('<KeyPress>', [ sub { shift; my $w = shift; $w->show_listbox() +; print Dumper($full +_PathMatchEntry->cget(-choices)); }, $full_PathMatchEntr +y ] ); print "Choices: " . Dumper($full_PathMatchEntry->cget(-choices)) . "\n +"; MainLoop; sub searchUpdate { #my ( $kernel, $session, $heap ) = @_[ KERNEL, SESSION, HEAP ]; my $full_PathCompactMatchEntry_ref = shift; #print Dumper(${$full_PathCompactMatchEntry_ref}->cget(-choices)); #print Dumper($full_PathCompactMatchEntry_ref); while (1) { sleep 1; my @bah; #my $bah = ${$full_PathCompactMatchEntry_ref}->cget(-choices); #@{$full_PathCompactMatchEntry_ref->cget(-choices)} = (); #push (@{$full_PathCompactMatchEntry_ref->cget(-choices)}, +[ "/dfgsdfgsdfgsfse/ertuy/" , "3534235523", "234232" ] ); push (@bah, [ "/dfgsdfgsdfgsfse/ertuy/" , "3534235523", "23 +4232" ] ); $$full_PathCompactMatchEntry_ref->configure(-choices => \@b +ah); #${$full_PathCompactMatchEntry_ref}->show_listbox(); #print Dumper(${$full_PathCompactMatchEntry_ref}->cget(-choice +s)); } }
Now, this simulates the problem quite well. I have tested with threads::shared and Thread::Queue::Any (both on a more complex @choices (with hashes in it aswell. Remember, this is a shortened version), and on the $full_PathMatchEntry widget), but no progress! I have also tested with POE, but no real progress there either! As you may see here, the idea is to change the @choices array (or somehow beeing able of changing the data which -choices points too), so the $full_PathMatchEntry shows the new data when doing ->show_listbox().

I'm totally out of ideas here now, as I've managed to make this work with less compless data (as standard $scalars). That is, sending the reference to the thread and read/change them. This also goes with widgets like JComboBox.

What/Why is something with $full_PathCompactMatchEntry_ref undefined when doing ${$full_PathCompactMatchEntry_ref}->configure(-choices => \@bah);?

And what is
"Attempt to free non-existent shared string '_TK_RESULT_', Perl interpreter: 0x25 6b72c at C:\Perl\site\lib/Tk/After.pm line 33."
all about? (I suspect it wants to free the @bah variable...?)

Suggestions to good debug tools for this is also good to know about!

Solvations? I would prefer to somehow beeing able of accessing the whole $full_PathMatchEntry from the searchUpdate thread. That way I have more I can do, than just sharing the data variable! (but now I get "Tk::Error: Can't call method "Call" on an undefined value at C:/Perl\site\lib/Tk/After.pm line 89."

Oh, and yes, I know about the ->after function you can do in Tk. But I dont have use of that here. I must have the searchUpdate as another thread, else the application isn't as smooth...

Thanks,
Ace

Replies are listed 'Best First'.
Re: Annoying threads share problem!
by castaway (Parson) on Oct 09, 2005 at 10:42 UTC
    Sorry, but you're out of luck. Sharing Objects of any kind between threads is not supported, and will not work at all. If you look in the threads::shared documentation under BUGS, you will see that blessed things cannot be shared.

    You *might* be able to get around it by using freeze/thaw (in Storable) to save and restore your object (all Tk widgets are objects), but as I've spent many a frustrated moment attempting to do similar, I'll just tell you that its not a fun thing to do.

    C.

      you will see that blessed things cannot be shared
      No, shared things can't be (usefully) blessed, which is quite different. This is valid code:
      my $x = bless [], 'X'; share $x;
      The main problem with shared objects is that their destructor currently gets called multiple times, once per thread.

      Dave.

        Perhaps you'd comment on the disparity between that and this?

        use threads; use threads::shared;; my $x:shared = bless [], 'X'; Invalid value for shared scalar at (eval 4) line 1, <STDIN> line 2.

        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.
        I haven't gotten it reliably working either way, can you give a working example?

        C.

      Come on! This is Perl! Must be more than one way doing it! ;) I'm curious on how it can work with JComboBox then... ?

      Maybe you have other ideas how to update the $full_pathMatchEntry widget?
        I'm curious on how it can work with JComboBox then... ?
        In Java all threads share a single address space. So although you can have a world of concurrency problems when writing threaded programs in Java, it's still perfectly possible to create complex objects in one thread and access them in another thread. And the AWT/Swing classes are largely thread-safe (for reading-type things anyway).
Re: Annoying threads share problem!
by Ace128 (Hermit) on Oct 09, 2005 at 12:22 UTC
    Thread::Queue::Any could be the solution, IF I had some bright idea to use it! I mean, the updateSearch would add to the queue, but how to set up a listener in the "Tk" part? This would need a thread, but then Im back to square one again... seems impossible!
      Hi, I have played with Tk and threads quite abit, and although I don't really understand all of the underlying magic, this is what I have found.

      When mixing threads and Tk code, you must create your threads before you call any Tk statements. In my threaded Tk apps, I first create the number of threads I want, put them to sleep, and control them thru shared scalars. Tk is not thread-safe, and if you try to setup some Tk code, then create a thread, it will fail with odd errors. Also, you shouldn't try to run a second Tk event loop in a thread, unless it's the only loop, i.e. no event loop in main. So you are left with a basic template, of 1 Tk-event-loop in main, and a bunch of worker threads( which are non-Tk ), which communicate with main thry shared scalars and shared arrays. This type of program style runs well.

      Now say you do get the above program setup to run. There is another problem. Tk's useful technique of being able to specify a reference in a -textvariable option, which automatically reflects the change in the reference's value, will NOT work across threads. So you when you wake up a thread, and tell it to do something, you will have to actively read the shared scalars(arrays) in main. This can be done with a timer set very fast, like

      my $timer = $mw->repeat(10,sub{ $x = $shared{'x'}; $y = $shared{'y'}; $mw->update; });
      It can all be done with careful planning.

      I'm not really a human, but I play one on earth. flash japh
        I forgot to mention this, but the searchUpdate thread is supposed to update data in question when user types stuff in the entry... So, I wanted to avoid to do a $mw->repeat(xx...) to update when not neccessary, thus somehow make the searchUpdate thread update! and not the Tk one... hope you see the problem I have becasuse I can't make the searchUpdate update/change the Tk widget when it needs too...