From: <ro...@vi...> - 2006-06-28 17:33:42
|
> Copying the dynamic bindings does not automatically make a library > thread safe. The side effect of the current arrangement is that you (or > preferrably the library author) is forced to think about threads a bit > more. that's true. on the other hand, it means that unless the author has explicitly exported a list of required dynamic variables (which might not even be known statically), i cannot use a library even if it *would* have been thread safe. > > Why are global variables special anyway? > > Huhh? Well, suffice it to say that specials are here to say. While quite > problematic with regards to their interactions with threads they are > useful in a number of situations. sorry. i meant global dynamic variables, as opposed to dynamic variables bound with a LET. i thought the example made that clear. i don't think that specials are a bad idea; i do think, though, that the implementation should make it as straightforward to use them in a multi-threaded context as when single-threaded. > The same example in code: > > (defun foo (fn) > (let ((*x* (cons 1 2))) > (declare (dynamic-extent *x*)) > (funcall fn))) > > Now if you do: > (foo (lambda () (make-thread (lambda () (sleep 1) (gc))))) > you might have just crashed the image. isn't that directly analagous to the following, which might similarly crash the image? (foo (lambda () (defparameter *y* *x*))) i.e. there's no telling how dynamic variables will be kept around, threads or no threads. > (defun foo (fn) > (let ((*x* (make-huge-object)) > (funcall fn))) > > Now if you do: > (foo (lambda () > (make-thread (lambda () (loop (print (eval (read))))))) > then the huge object is never unallocated. however, at least if you're aware of the issue, you could do: (defun foo (fn) (let ((*x) (make-huge-object)) (funcall fn) (setf *x* nil))) cheers, rog. |