develooper Front page | perl.ithreads | Postings from August 2002

Re: Thread-Tie-0.01

From:
Nick Ing-Simmons
Date:
August 12, 2002 02:46
Subject:
Re: Thread-Tie-0.01
Message ID:
20020812094553.1396.2@bactrian.elixent.com
Elizabeth Mattijsen <liz@dijkmat.nl> writes:
>At 12:12 PM 8/11/02 +0100, Nick Ing-Simmons wrote:
>> >The Thread::Tie module is a proof-of-concept implementation of another
>> >approach to shared variables.  Instead of having shared variables exist
>> >in all the threads from which they are accessible, shared variable exist
>> >as "normal", unshared variables in a seperate thread.  Only a tied object
>> >exists in each thread from which the shared variable is accesible.
>>That is actually exactly what threads::shared is supposed to do as well.
>>The only difference being that the "separate thread" has a shadowy
>>existance
>
>Aha!  So maybe there the "2 other threads were running" message is coming 
>from, when you only started one other thread.  

It is a posibility.

>Does this shadowy thread run 
>always, even if you don't have threads::shared ?

I think threads::shared bootstrap calls it into being.


>
>
>>  and the client threads assume its identity (briefly) to become
>>their own server - which was supposed to be an optimization :-(
>
>Maybe it is from a CPU point of view, but it definitely isn't from a memory 
>point of view.  Because now in an array each element will need to be tied 
>to the shared magic.  

It isn't quite that bad. When you do a FETCH the returned value gets 
tie - it should be freed when all references to the FETCHed value
go out of scope.

>In my approach only the object to which the array is 
>tied, contains shared elements.  Inside the thread, the array is an array 
>just like any other array.  Which saves a lot on magic.  Or am I mistaken 
>in this?

As far as I can tell your approach and the one I was aiming at are
identical (aside from the showdow thread thing).
However as I am doing all the tie and FETCH/STORE etc. in XS code 
it is easier to make mistakes.

>
>
>> >=item memory usage
>> >Shared variables in this approach are truly shared.  The value of a variable
>> >only exists once in memory.  This implementation also circumvents the memory
>> >leak that currently (threads::shared version 0.90) plagues any shared array
>> >or shared hash access.
>>As the threads::shared scheme is _supposed_ to be exactly as you describe
>>there _should_ be no difference here.
>
>Apart from the huge memory leak that makes it impossible to use shared 
>arrays and hashes in a production environment.

So let us find it.

>
>
>> >=item tieing shared variables
>> >Because the current implementation uses tie-ing, you can B<not> tie a shared
>> >variable.  The same applies for this implementation you might say.  However,
>> >it B<is> possible to specify a non-standard tie implementation for use
>> >B<within> the thread.  So with this implementation you B<can> C<tie()> a
>> >shared variable.  So you B<could> tie a shared hash to a DBM file à la
>> >dbmopen() with this module.
>>This is still an advantage of your scheme - as the server-thread is
>>"visible" its variable can be tied using normal approaches.
>
>Indeed.  You can now have a shared filehandle that is tied using a module 
>that doesn't know anything about threads.  Such as a DBM file.
>
>I think the main disadvantages of Thread::Tie (at least under Linux) are:
>
>- threads->yield doesn't seem to yield.
>This means you're burning CPU needlessly until your timeslice is over.

ick - can we find something that _does_ yield?

>
>- a cond_wait, cond_signal pair is not guaranteed to pass the lock
>If you have a thread waiting at a cond_wait, and another thread is doing a 
>cond_signal, the thread in cond_wait is _not_ guaranteed to get the lock() 
>again.  Not even if you're just using two threads!  For example:
>
>Server thread:
>
>   {lock( $shared );
>    warn "server relinquishing control\n";
>    cond_wait( $shared );
>    warn "server in control again\n";
>   }
>
>
>Client thread:
>
>   {lock( $shared );
>    warn "signalling server to act 1\n"
>    cond_signal( $shared );
>   }
>   warn "unlocked 1, waiting for lock 2\n";
>   {lock( $shared );
>    warn "signalling server to act 2\n"
>    cond_signal( $shared );
>   }
>   warn "unlocked 2\n";
>
>You will see that the client thread is able to gain the lock again after a 
>cond_signal (about 75% of the time, under Linux, on my development box) 
>before the server thread receives the signal.

You normally need a pair of semaphores to exchange requests between 
a client and a server - but note that a "condition variable" is NOT 
quite the same as a semaphore. Which is why higher level things like 
queues are so popular.

>
>Because of this behaviour you need to have a seperate semaphore that is 
>checked by the client to see whether the server actually received the 
>(previous) signal before preceding.  And of course, when the client sees 
>that it gained the lock prematurely, you need to yield().  Something ugly like:
>
>     my $tries;
>     AGAIN: while (1) {
>         threads->yield if $tries++;
>         {lock( $control );
>          next AGAIN if defined( $$control );
>
>And of course, at least under Linux, this eats CPU on a massive scale 
>because yield() actually doesn't yield.  ;-(
>
>
>Liz
-- 
Nick Ing-Simmons
http://www.ni-s.u-net.com/




nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About