3

How to convey all of the current thread's bindings to another thread? To be specific, I need the following snippet to print 2 (not 1) to stdout:

(defvar *foo* 1)

(let ((*foo* 2))
  (bordeaux-threads:make-thread (lambda () (print *foo*)))) ;; prints 1

Of course I could copy *foo*'s value by hand, like this:

(let ((*foo* 2))
  (bordeaux-threads:make-thread
   (let ((foo-binding *foo*))
     (lambda () 
       (let ((*foo* foo-binding))
         (print *foo*)))))) ;; prints 2

but is there anything that will allow to copy all of them at once?

OlegTheCat
  • 4,443
  • 16
  • 24

1 Answers1

4

The API is explicit regarding variable sharing:

The interaction between threads and dynamic variables is in some cases complex, and depends on whether the variable has only a global binding (as established by e.g. DEFVAR/DEFPARAMETER/top-level SETQ) or has been bound locally (e.g. with LET or LET*) in the calling thread.

1.

Global bindings are shared between threads: the initial value of a global variable in the new thread will be the same as in the parent, and an assignment to such a variable in any thread will be visible to all threads in which the global binding is visible.

2.

Local bindings are local to the thread they are introduced in, except that

3.

Local bindings in the the caller of MAKE-THREAD may or may not be shared with the new thread that it creates: this is implementation-defined. Portable code should not depend on particular behaviour in this case, nor should it assign to such variables without first rebinding them in the new thread.

So make the the binding global and not local seems to be the easiest (not implementation dependent) route.

@coredump also suggests to checkout the *default-special-bindings* list for a possible sharing methodology:

This variable holds an alist associating special variable symbols with forms to evaluate for binding values. Special variables named in this list will be locally bound in the new thread before it begins executing user code.

This variable may be rebound around calls to MAKE-THREAD to add/alter default bindings. The effect of mutating this list is undefined, but earlier forms take precedence over later forms for the same symbol, so defaults may be overridden by consing to the head of the list.

Forms are evaluated in the new thread or in the calling thread? Standard contents of this list: print/reader control, etc. Can borrow the Franz equivalent?

kabanus
  • 24,623
  • 6
  • 41
  • 74
  • See also the note about `*default-special-bindings*` – coredump Jun 19 '18 at 11:41
  • `*Default-special-bindings*` is the straightforward way. Falling back to global, effectively non-special behaviour does not seem advisable. – Svante Jun 19 '18 at 19:58
  • Are you sure it would be easier if you want to change a variable in the main thread? – kabanus Jun 19 '18 at 20:54
  • I am generally sure that it would be easier not to change global variables at all (as opposed to a dynamic re-binding). If you need communication between threads (or processes, or whatever), use channels/mailboxes/sockets/queues/whatever. – Svante Jun 20 '18 at 14:27
  • I didn't mean from a system design perspective, I meant for a quick and dirty little application "meant just for me". But I see your point, I'll add the warning in a bit. – kabanus Jun 20 '18 at 14:39