Stephen White <spwhite / chariot.net.au> wrote:
>
>I've been playing around with multi-threading. I notice that there are
>different models for each of the options. Some split and rejoin. Some
>run in parallel with spin locks. Some are co-operative.
>
>None of them are really satisfactory. I want threading to be part of
>the language, to be assimilated by the Borg of Syntax. Regexp's were
>assimilated, so threading should be conquerable.

I think that pervasive threading when not asked for is
very dangerous.  Here be dragons.

>After much consideration, here's a proposed model for threading. First
>comes the concept, then comes the optimisations.
>
>Normally, threading is provided as a library and the default number of
>threads is one. What if the object oriented concept were extended to
>give every object its own thread?

I would worry that you would wind up with too many
threads.

Secondly synchronization requires locking.  If you
have automatic locking going on then it either needs
to be very coarse-grained (in which case you do not
get good concurrency) or else it is fine-grained in
which case you wind up with a lot of possibilities
for deadlocks.

>Here's how it would work:
>
>               Object A                   Object B
>               ========                   ========
>     1         b = B.new                  <created>
>     2         x = b.status               status begin
>     3           paused                     running
>     4           paused                   status end
>     5         b.demo                     demo begin
>     6         b.check                      running
>     7           paused                     running
>     8           paused                   demo end
>     9         y = b.status               check begin
>    10           paused                   check end
>    11         p x, y
>
>This looks more complicated than it is... The basic idea is that each 
>object
>has its own thread, so this guarantees that functions in an object will not
>run out of order.
>
>This eliminates problems with re-entrancy and race conditions within an
>object. It can access instance variables safely, and class/globals with
>no more trouble than before.

Instance variables are themselves threads.  What if my
object assumes that my instance variables stay put while
I am accessing them?  That is a common assumption.

Likewise many will (I certainly would) assume that if
I make 3 method calls in order that they will happen in
order.  Changing that out behind my back could be a very
bad idea.  Consider method calls to []= for an example.

>The rules are:
>
>   An object making a method call will be suspended if it uses the result
>   from the method call (3, 4, 10), or the called object is busy (7, 8).
>
What if an instance variable of the object is busy?  In
some sample code that I sent you that could happen.

>   An object making a method call will return immediately if it doesn't use
>   the result and the called object is idle (6). Another approach would be 
>to
>   allow method calls to queue up but this could get a bit intense. :)

Scenario.  A calls B, B yields to a block that calls A
again.  Do we now have deadlock?

>The problem with this are the parameters.
>
>               Object A                   Object B
>               ========                   ========
>     1         b = B.new                  <created>
>     2         a = [0, 1, 2, 3, 4]
>     3         b.change a                 x[2] = nil
>
>               p a   ->   [0, 1, nil, 3, 4]
>
>How could this be handled? Suspend if passing parameters? Freeze objects
>passed between objects? I think the best solution would be to allow the
>calling process to continue, but suspend on access to the objects passed
>in the parameters. This mechanism would also handle return values, so the
>calling object can continue until the return value is used. Eg:
>
>   x = a.func
>   y = b.func
>   z = c.func    # At this point, three threads are running
>   i = x + 1     # Pauses until a.func returns, to provide value for x
>   j = i + y + z # Pauses until y, and z are available
>
Note that Ruby is very much based on constantly passing
messages between objects.  I suspect that it would be
harder to do this efficiently if those objects had to
be assumed to be in different threads.  This would be
very much true if at some point the idea was opened up
of making the threading model use OS visible threads.
(Which is something that I predict is likely to be a
future desire.)

>Regardless of the final design, I like the idea of every object being like 
>a
>process, able to receive and respond to requests in their own time. Being
>able to fire off messages to other objects in a universe where everything 
>is
>inherently multi-threaded sounds appealing to me.

An idea I have heard very good things about in the Perl
world which might fit very well indeed into Ruby is POE.

http://search.cpan.org/doc/RCAPUTO/POE-0.12/POE.pm

Take a look at it and see whether what they describe
would do what you want.

>Like OO in Ruby, the multi-threaded nature of this would not be readily
>apparent as the syntax is unchanged. Calls still return results, multiple
>calls still occur in sequence, and parameters are still passed back and
>forth as per normal.

I thought you said that if the return was not looked at
then things were parallelized?

>The language is just smart enough to run objects in parallel when things 
>are
>nicely decoupled. In effect, it's a freebie reward for writing good OO.
>
>The implementation could be along the lines of assigning a Thread value
>to every Object which is usually nil, then re-using threads. There would
>be a slight interpreter slowdown from having to check method calls for
>thread association, but I can't see it taking up much time.

I can.

>What do you think? Like the idea? Would this kind of multi-threading be
>able to handle your multi-tasking problems? Can you see any problems with
>implementing this concept?
>
I think I listed most of my problems with implementing this.

For more of my thoughts on threading, see
http://206.170.14.76/index.pl?node_id=29620

An apparently unrelated, but IMHO very relevant, discussion
on OS design is at:

http://www.bitmover.com/talks/cliq/slide01.html

Trying to separate out applications into fine-grained
intercommunicating components is very hard, trouble
prone, and leads to a lot of overhead.  Far better if
you can is to keep it as much coarser-grained
decoupled components.  That leaves you more room later
to do things like spread it out across a cluster, etc.

I don't know how the distributed Ruby solutions tackle
this, but they are worth a look, along with the POE
link I gave earlier.

Cheers,
Ben
_________________________________________________________________
Get your FREE download of MSN Explorer at http://explorer.msn.com