[Openmcl-devel] Thread-local bindings
brooks.martin at sympatico.ca
Sat Jun 15 13:14:47 PDT 2019
Thanks; I stand corrected on both counts.
I am guessing the last call to process-run-function is supposed to have :thread-3 throughout.
Assuming this is so, what I see is:
THREAD1 GLOBAL-FOO 1
MAIN-THREAD GLOBAL-FOO 2
THREAD2 THREAD-2-FOO 3
THREAD3 THREAD-3-FOO 1
THREAD1 GLOBAL-FOO 4
MAIN-THREAD GLOBAL-FOO 5
THREAD2 THREAD-2-FOO 6
THREAD3 THREAD-3-FOO 2
THREAD1 GLOBAL-FOO 7
MAIN-THREAD GLOBAL-FOO 8
THREAD2 THREAD-2-FOO 9
THREAD3 THREAD-3-FOO 3
Thread-1, thread-2 and main-thread take turns incrementing the global binding of *cnt*, whereas thread-3 increments its local binding.
So, yes — the global binding is shared across the top level — was that your point?!?
I am looking for words; perhaps this is better:
The dynamic extent of special lambda bindings has no meaning except in the thread that established those bindings.
The point upon which I initially hit my head was the case where a new thread is launched from within the extent of such special lambda bindings.
Those bindings have no meaning for the new thread.
Except … unless the new thread’s function is specially designed to promulgate those bindings, so that code in the new thread proceeds in the dynamic context of the parent thread:
(process-run-function :my-thread #’(lambda (special-var) …) special-var)
> On Jun 15, 2019, at 12:08 PM, Ron Garret <ron at flownet.com> wrote:
> On Jun 15, 2019, at 6:43 AM, martin <brooks.martin at sympatico.ca> wrote:
>> — “Dynamic extent” refers to time within a single thread, and does have meaning across multiple threads.
> My guess is that you meant to say that it does NOT have meaning across multiple threads, but this is not correct. It does. See below.
>> — Funcall is a function; process-run-function is a special form.
> No, they are both functions:
> ? #'funcall
> #<Compiled-function FUNCALL #x30000007F9FF>
> ? #'process-run-function
> #<Compiled-function PROCESS-RUN-FUNCTION #x300000401C7F>
> Try this:
> (defvar *foo* 'global-foo)
> (defvar *cnt* 0)
> (let ((lock (make-lock))
> (stream (if (find-package :hemlock-ext)
> (funcall (find-symbol "TOP-LISTENER-OUTPUT-STREAM" :hemlock-ext))
> (defun out (s &rest args)
> (with-lock-grabbed (lock)
> (apply 'format stream s args)
> (terpri stream))))
> (defun print-foo (thread-id)
> (dotimes (i 3)
> (out "~A ~A ~A" thread-id *foo* (incf *cnt*))
> (sleep 0.1)))
> (defun test ()
> (process-run-function :thread-1 (lambda () (print-foo :thread1)))
> (process-run-function :thread-2 (lambda () (let ((*foo* :thread-2-foo))
> (print-foo :thread2))))
> (process-run-function :thread-2 (lambda () (let ((*foo* :thread-3-foo)
> (*cnt* 0))
> (print-foo :thread2))))
> (print-foo :main-thread)
> (sleep 0.1)
More information about the Openmcl-devel