in reply to Re: Annoying threads share problem!
in thread Annoying threads share problem!

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

Replies are listed 'Best First'.
Re^3: Annoying threads share problem!
by Ace128 (Hermit) on Oct 09, 2005 at 14:01 UTC
    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...
      It sounds to me like you have to clarify and rethink your design. If you want to update something, when someone types something into the entrybox. Here is some code which does what your first example attempts to do.

      P.S. Use code blocks around your code examples.

      #!/usr/bin/perl use warnings; use strict; use Tk; use Tk::MatchEntry; use threads; use threads::shared; my %shash; my %hash; my @choices; share $shash{'go'}; share $shash{'die'}; share @choices; $shash{'go'} = 0; $shash{'die'} = 0; @choices = ( "01234", "345345", "64364" ); $hash{'thread'} = threads->new(\&work); my $mw = MainWindow->new( -title => "MatchEntry Test" ); #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' ); $full_PathMatchEntry->focus; $full_PathMatchEntry->bind( '<KeyPress>', [ sub { shift; my $w = shift; $w->show_listbox(); }, $full_PathMatchEntry ] ); $mw->Button(-text=>'Do_Thread', -command=> sub { $shash{'go'} = 1; $mw->after(1000); $full_PathMatchEntry->configure(-choices => \@choice +s); })->pack(); MainLoop; sub work{ $|++; while(1){ if($shash{'die'} == 1){ goto END }; if ( $shash{'go'} == 1 ){ push( @choices, "/dfgsdfgsdfgsfse/ertuy/" ); $shash{'go'} = 0; #turn off self before returning }else { sleep 1 } } END: }

      I'm not really a human, but I play one on earth. flash japh
        Thanks, but this is also something I've been doing more or less, but this solution is just making the problem halfsolved so to speak. I mean, the
        $mw->after(1000);
        is there just to make time for the
        &work()
        thread to finnish it's job, so the
        $full_PathMatchEntry->configure(-choices => \@choices);
        will actually change something! This is all nice, but its still not the
        &work()
        that changes the
        $full_PathMatchEntry .
        Maybe this isnt possible as it is now, although I bet there is...
        If we break it down to the main problem, this workaround has to be done since the
        $full_PathMatchEntry
        can't be shared. Now, how about sharing
        @choices ?
        This would all be good, if we didnt had to do:
        $full_pathMatchEntry->show_listbox();
        I mean, here we still need to somehow notify the widget that something has changed (thing is that the change to the @choices can happen, and if we don't type anything more, then we won't resisplay the listbox), but how to do that? We can't have a listener in the Tk thread, since then we can't type anything...