[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

DYNAMIC-WIND vs. multi-processing



re: If users want to multi-process, they should use a concurrent language, 
    which straight, simple R4RS Scheme is not. CALL/CC with or without
    DYNAMIC-WIND is not the way to do concurrency.

"Multi-tasking" is a different, somewhat less capable but certainly less
complex, concept than "concurrency" (I presume by the latter, you mean at
least that the execution model is designed to scale up smoothly from 1 to
2, and hence from 1 to "many", parallel processors).  Still, Multi-tasking 
is a very useful concept for the uniprocessor model.

But I agree wholeheartedly with your conclusion that "CALL/CC with or 
without DYNAMIC-WIND is not the way to do concurrency."  See the counter
point for the paragraph below.



re: Further, I do not think DYNAMIC-WIND-invoked-on-every-thread-switch is the
    way to manage thread-shared state that needs to be in a particular 
    configuration while some thread is running -- what Gerry says RMS thought 
    it up for.  Again, this model doesn't handle true parallel execution.  An 
    example: suppose I wanted my threads to each have their own Unix current 
    working directory, so I had DYNAMIC-WIND do chdir's going in and cwd's 
    coming out. Then on every thread switch, I could do an (expensive, slow) 
    mutation of the shared process state to put each thread in his own 
    configuration of that state. But how do I model running threads on a 
    parallel processor, where more than one thread can execute at once? 
    CALL/CC and DYNAMIC-WIND don't handle this. I think a thread model should 
    have semantics that are independent of whether you are using a
    uniprocessor or multiprocessor implementation.


That's a high cost to put onto the notion of "threads" -- that they must
be a capable model for concurrent parallel exection; but it is not an
unreasonable one.  Having done so, there is an obvious implication that
is borne out by history. To wit:

Lucid's commercial Common Lisp product is a "shallow-bound" implementation, 
and Multi-processing is accomplished by an equivalent of "DYNAMIC-WIND-
invoked-on-every-thread-switch" (and other tricks).  However, when we began 
work on QLISP--a queue-based multi-processor model for Common Lisp---we had 
to abandon "shallow-binding" and go over to "deep-binding".  It's not hard 
to see that a shared-memory model must not communicate fluid state simply 
by bashing globally-visible cells.

On the other hand---with 15 years of hindsight available---we didn't make 
the mistake of confusing "deep binding" with "spaghetti stacks".  The latter
is a model from the early 1970's that rolled dynamic variable state up with 
execution control state into a context not unlike that required for first-
class continuations.  This mixture proved to be not only semantically 
confusing, and implementationally cumbersome, but ultimately not even what 
was desired for the model of exectuion control state (the desired model was 
"stack groups"---each processor with its own private control stack).

In conclusion: don't be seduced by superficial similarities between 
CALL/CC and rugged concurency.




-- JonL --