Some notes on Lisp, specifically Common Lisp.
Common Lisp's special variables are a wonderful thing. They allow you to do things which would be very hard to do without them. In particular, they allow you to maintain `dynamic state' - information about the state of some process which can be established and is then visible within the dynamic scope of its establishing form, and which will absolutely definitely be disestablished when the establishing form exits.
It's often thought that special variables can be simulated by an explicit shallow binding scheme. So long as there are global variables then the scheme would work something like this.
(let ((old *global-variable*)) (unwind-protect (progn (setf *global-variable* new) ...code...) (setf *global-variable* old)))
So ...code... would see the dynamic `binding' of
*global-variable*. This whole thing would then be
hidden away in a macro called something like
Of course, this can't work in the case of a multithreaded Lisp, because all the other threads that execute while the `binding' is in effect will also see the `binding', which is precisely what you don't want.
The fix often proposed for this problem is to add a
special operator similar to Scheme's
operator. This is a generalised
unwind-protect - it
allows you to specify two sets of actions - one that happens when
the stack is unwound for any reason - including a thread switch -
and one that happens when it is rewound for any reason -
including a thread switch. Scheme needs this because it has
call/cc, which can cause just this kind of multiple
exit/entry to happen. In fact the mechanism proposed for CL is
not really like
unwind-protect, because you would not
unwind-protect to do its thing on a
The theory then is that, on a thread switch away from a thread,
the stack would be `unwound', and the
form would catch this, and would restore the old value of the
global. When a switch occurred back into the thread, the stack
would be rewound, and the
dynamic-wind form would
reestablish the `bound' version of the global. The end result is
to provide a mechanism which allows you to cool your own
shallow-binding scheme. Further, once you have this mechanism you
can use it for any kind of state, for instance you could
dynamically bind functions. Eventually, you'd end up with a macro
letf which would be to
setf is to
This is a nice idea, but it's not a solution to the problem. It presupposes an implementation of multithreading where there are thread switches: in other words an implementation where multiple processors are emulated by one processor. On an implementation of multithreading where there really are multiple processors, there may be no thread switches - multiple threads can genuinely all run at once. So, on such an implementation this technique wont work, either for dynamic variables or any other kind of dynamic state. In general, if you want dynamic binding it has to be done at the level of the implementation, you can't fake it.