verec <verec@mac.com> wrote:
+---------------
| I'm wrapping my head around Thomas solution to try and understand
| how his solution is different/solves the threading issue.
| So far, my understanding of his code is that the magic happens
| with the use of progv ...
+---------------
Not really; PROGV per se is a red herring. It has nothing to do
with the core issue, which is this: Even though the CLHS says
nothing about "threading", the Common Lisp community -- and
especially the community of implementors (competitors though
they might be!) -- have generally come to a consensus of how
dynamic variables should behave in the presence of threading
[any kind of threading -- green, "native", POSIX, etc], which
is roughly the following [apologies if I don't use exactly the
proper terminology]:
In the absence of threading [or with only one thread active],
things behave exactly as in CLHS 3.1.2.1.1.2 "Dynamic Variables":
At any given time, all dynamic variables with a given name refer
to exactly one binding, either in the dynamic environment or in
the global environment.
where "the global environment", sometimes called the top-level
environment, is simply whatever contains the binding for a special
variable when it is not dynamically bound. Any assignment [with
SETF/SETQ or things that expand to them such as INCF or PUSH] affects
only the single, current dynamic binding. During the dynamic extent
of a LET- or LAMBDA-binding, there is no way to change the original
"global" value or any of the values saved on the "stack" of dynamic
bindings. Also, (SETF (SYMBOL-VALUE sym) ...) is required to act on
the current dynamic binding. See the CLHS for many other gory details.
*With* threading, the model changes only slightly, but *VERY*
significantly, as follows:
1. All of the threads that have *not* LET- or LAMBDA-bound a special
variable continue to share a single view of a global or top-level
value. Any assignment (SETF) to that variable is seen by all threads
which have *not* LET- or LAMBDA-bound that special variable.
2. Any thread which *does* LET- or LAMBDA-bind a special variable
creates a *new* conceptual variable and related "stack" of dynamic
bindings which is private to that thread [and in some (most?)
implementations, its descendents, assuming they don't further bind
it themselves]. Assignments to or further dynamic rebindings of
the variable within that thread are seen *only* by that thread [and
descendents], *NOT* by any of the other threads [which see either
the top-level binding or their own, private LET- or LAMBDA-bindings].
Thus, threading replaces the CLHS notion that a special variable
always has a *single* binding [which can be dynamically bound in
a *single* conceptual "stack"] with the concept that the first
LET- or LAMBDA-binding of a given special variable by a given
thread creates a *new* per-thread binding [and associated conceptual
"stack" of further dynamic bindings].
So how does this apply to your question about "dynamic functions"?
Well, since the above "threading model of dynamic variables" is by
now so firmly established in the CL community as "the right way",
there is a natural expectation that any implementation of "dynamic
functions" would behave EXACTLY THE SAME WAY with respect to threading.
That is, that any DFLET form executed within a thread would create
a new function binding that would be seen ONLY WITHIN THAT THREAD
(and descendants), just as the above model does for special variables.
And *that* is why various people have been *strongly* suggesting
that you make your dynamic function facility store the current
binding in a per-function-name special variable and use FUNCALL
(or APPLY) indirection through the special variable -- because,
if you do that, the "expected" (by the community) behavior for
things dynamic in the presence of threads will "just happen"
automatically in any implementation that follows the consensus
model of threading and special variables. And if you *don't*
do that, then it won't.
Capische?
-Rob
-----
Rob Warnock <rpw3@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607