From: Mark H.
Subject: SYMBOL-FUNCTION and thread implementations
Date: 
Message-ID: <1185211311.596070.67120@z24g2000prh.googlegroups.com>
Would it be accurate to assume that in all reasonable multithreaded
CL's out there, calling a named function FOO does NOT involve locking
(SYMBOL-FUNCTION 'FOO) with a mutex or something of the sort?

This would make sense from the "code == data" perspective (no implicit
locking of user-defined objects, including functions) but I wasn't
sure if there was a particular CL out there that does this for its own
nefarious purposes.  I poked around the sbcl-devel mailing list
archives and didn't find any mention of implicitly locking users'
function definitions, but no mention may not mean it isn't there, and
I wasn't feeling brave enough to read the source code. ;-)  I haven't
checked the other truly multithreaded Lisps' devel list archives yet.

mfh

From: Rob Warnock
Subject: Re: SYMBOL-FUNCTION and thread implementations
Date: 
Message-ID: <TaKdnaey8_Px7zjbnZ2dnUVZ_umlnZ2d@speakeasy.net>
Mark H. <············@gmail.com> wrote:
+---------------
| Would it be accurate to assume that in all reasonable multithreaded
| CL's out there, calling a named function FOO does NOT involve locking
| (SYMBOL-FUNCTION 'FOO) with a mutex or something of the sort?
+---------------

I should think so, since unlike the SYMBOL-VALUE slot of a symbol,
which is rebound *dynamically* by LET, the SYMBOL-FUNCTION slot
of a symbol is rebound *lexically* by FLET (or LABELS), and thus
(unlike the SYMBOL-VALUE slot) doesn't need to interact with the
threading system at all.[1]  E.g.:

    > (defvar foo 'global-value)

    FOO
    > (defun foo () 'global-function)

    FOO
    > (defun bar () (list foo (foo)))

    BAR
    > (bar)

    (GLOBAL-VALUE GLOBAL-FUNCTION)
    > (let ((foo 'local-value))
	(flet ((foo () 'local-function))
	   (list* foo (foo) (bar))))

    (LOCAL-VALUE LOCAL-FUNCTION LOCAL-VALUE GLOBAL-FUNCTION)
    > 

Capische?


-Rob

[1] Well, unless you're changing the value of the SYMBOL-FUNCTION
    slot yourself, in which case since you've caused the issue it's
    up to you to fix it (e.g., with explicitly-coded locks).

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Mark H.
Subject: Re: SYMBOL-FUNCTION and thread implementations
Date: 
Message-ID: <1185293864.239759.298170@e9g2000prf.googlegroups.com>
On Jul 23, 8:30 pm, ····@rpw3.org (Rob Warnock) wrote:
> Capische?

Yup, that makes sense, though I'm still not 100% clear on how those
two binding mechanisms are implemented in a multithreaded CL.  SBCL
doesn't let threads inherit dynamic bindings:

http://www.sbcl.org/manual/Special-Variables.html#Special-Variables

which, after reading your explanation, makes more sense.  Otherwise,
SBCL would have to keep the dynamic binding context around for the
thread, no matter how long the thread takes to complete (_if_ it
completes -- it could be killed before it even runs).

> [1] Well, unless you're changing the value of the SYMBOL-FUNCTION
>     slot yourself, in which case since you've caused the issue it's
>     up to you to fix it (e.g., with explicitly-coded locks).

Yeah, I'm not planning on fiddling with function -> name bindings in
any of my threads -- I just wanted to make sure that calling a named
function in a single thread doesn't involve thread synchronization.

Many thanks!
mfh
From: Rob Warnock
Subject: Re: SYMBOL-FUNCTION and thread implementations
Date: 
Message-ID: <k7udnfYfnIhTVjvbnZ2dnUVZ_j2dnZ2d@speakeasy.net>
Mark H. <············@gmail.com> wrote:
+---------------
| ····@rpw3.org (Rob Warnock) wrote:
| > Capische?
| 
| Yup, that makes sense, though I'm still not 100% clear on how those
| two binding mechanisms are implemented in a multithreaded CL.  SBCL
| doesn't let threads inherit dynamic bindings:
| 
| http://www.sbcl.org/manual/Special-Variables.html#Special-Variables
| 
| which, after reading your explanation, makes more sense.  Otherwise,
| SBCL would have to keep the dynamic binding context around for the
| thread, no matter how long the thread takes to complete (_if_ it
| completes -- it could be killed before it even runs).
+---------------

Yes, SBCL's ancestor, CMUCL, didn't permit inheriting dynamic bindings
either, and for the same reasons.

Hmmm... But SBCL's MAKE-THREAD appears to have lost something useful
from CMUCL's MP:MAKE-PROCESS, namely, the ability to pre-establish a
set of dynamic bindings for a new thread:

    cmu> (describe 'mp:make-process)

    MAKE-PROCESS is an external symbol in the MULTIPROCESSING package.
    Function: #<Function MULTIPROCESSING:MAKE-PROCESS {102C0BD1}>
    Function arguments:
      (function &key (name "Anonymous") (run-reasons (list :enable))
	             (arrest-reasons nil) (initial-bindings nil))
    Function documentation:
    ...
    :INITIAL-BINDINGS
	  An alist of initial special bindings for the process.  At
	  startup the new process has a fresh set of special bindings
	  with a default binding of *package* setup to the CL-USER
	  package.  INITIAL-BINDINGS specifies additional bindings for
	  the process.  The cdr of each alist element is evaluated in
	  the fresh dynamic environment and then bound to the car of the
	  element.

which you can use to effectively "inherit" from a select set of the
parent thread's current dynamic bindings this way:

    (let ((vars     '(*foo* *bar* *baz*))
	  (vals (list *foo* *bar* *baz*)))
      (mp:make-process #'new-thread-func
		       :initial-bindings (pairlis vars vals)))

Though I suppose you could always simulate it in SBCL by using PROGV
[which is exactly how CMUCL's MP:MAKE-PROCESS did it under the hood!]:

    (let ((vars     '(*foo* *bar* *baz*))
	  (vals (list *foo* *bar* *baz*)))
      (mp:make-process (lambda ()
			 (progv vars vals
			   (new-thread-func)))))

But of course, these are only inherited *values* of the parent's
current dynamic bindings, not the dynamic values themselves.
[That is, if after the child is running either the parent or
the child SETF's one, the other thread won't see the change.]


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607