Lisp HUG Maillist Archive

Special vars and threads.

Hi all,
 I'm hoping that someone can clear up my confusion regarding
 special variables and threads.

  My understanding is that running the following should print
  '*my-var* is T' to standard out. I seem to think the binding
  of *my-var* at this point will be the binding for the
  process being created. 
 
 (defvar *my-var* nil)

 (defun test-it () 
  (mp:process-run-function
    "Test" nil
    #'(lambda () 
        (format #.*standard-output* "*my-var* is ~A.~%" *my-var*))))
 
 (let ((*my-var* t))
   (test-it))

 The only reason I can think of is that mp:process-run-function
 doesn't invoke the lambda form itself but puts it onto some
 sort of stack which then schedules it to run, at which point 
 my binding of *my-var* is not in effect.

 Is this correct, and if it is then is there a way to achieve 
 the same effect?
  
Thanks,
 Sean.

-- 
"My doctor says that I have a malformed public-duty gland and a
 natural  deficiency in moral fibre," he muttered to himself, "and
 that I am therefore excused from saving Universes."
 - Life, the Universe, and Everything     Douglas Adams.


Re: Special vars and threads.

On 25 May 2005 10:58:29 +0200, Sean Ross <sdr@jhb.ucs.co.za> wrote:

>   My understanding is that running the following should print
>   '*my-var* is T' to standard out. I seem to think the binding of
>   *my-var* at this point will be the binding for the process being
>   created.
>  
>  (defvar *my-var* nil)
>
>  (defun test-it () 
>   (mp:process-run-function
>     "Test" nil
>     #'(lambda () 
>         (format #.*standard-output* "*my-var* is ~A.~%" *my-var*))))
>  
>  (let ((*my-var* t))
>    (test-it))

For this to work you have to bind MP:*PROCESS-INITIAL-BINDINGS* to

  (cons '(*my-var* . *my-var*) mp:*process-initial-bindings*).

See Nick Levine's explanation here:

  <http://cl-cookbook.sourceforge.net/process.html>

Cheers,
Edi.


Re: Special vars and threads.

At 25/05/2005 10:58, Sean Ross wrote:

>Hi all,
>  I'm hoping that someone can clear up my confusion regarding
>  special variables and threads.
>
>   My understanding is that running the following should print
>   '*my-var* is T' to standard out. I seem to think the binding
>   of *my-var* at this point will be the binding for the
>   process being created.
>
>  (defvar *my-var* nil)
>
>  (defun test-it ()
>   (mp:process-run-function
>     "Test" nil
>     #'(lambda ()
>         (format #.*standard-output* "*my-var* is ~A.~%" *my-var*))))
>
>  (let ((*my-var* t))
>    (test-it))


Hello Sean,

Try the following instead.

First of all, eval (read-line *terminal-io*) to show the console to see the output

(defun test-it ()
   (mp:process-run-function
     "Test" nil
     (lambda ()
       ;; t or *standard-output*
       (format t "~& #.*standard-output*: ~s" #.*standard-output*)
       (format t "~&*my-var* is ~A." *my-var*))))


To output in the Output tab:

(defun test-it ()
   (let ((mp:*process-initial-bindings*
          (append '((*standard-output* . mp:*background-standard-output*)
                  ;(*trace-output* . mp:*background-standard-output*)
                  ;(*error-output* . mp:*background-standard-output*)
                    )
                  mp:*process-initial-bindings*)))
     (mp:process-run-function
      "Test" nil
      (lambda ()
        ;; t or *standard-output*:
        (format t "~& #.*standard-output*: ~s" #.*standard-output*)
        (format t "~&*my-var* is ~A." *my-var*)))))

look at the output and at mp:*process-initial-bindings* in the documentation.

Francis



>  The only reason I can think of is that mp:process-run-function
>  doesn't invoke the lambda form itself but puts it onto some
>  sort of stack which then schedules it to run, at which point
>  my binding of *my-var* is not in effect.
>
>  Is this correct, and if it is then is there a way to achieve
>  the same effect?
>
>Thanks,
>  Sean.
>
>--
>"My doctor says that I have a malformed public-duty gland and a
>  natural  deficiency in moral fibre," he muttered to himself, "and
>  that I am therefore excused from saving Universes."
>  - Life, the Universe, and Everything     Douglas Adams.


Re: Special vars and threads.

On Wed, May 25, 2005, 04:58, Sean Ross <sdr@jhb.ucs.co.za> wrote
>
>Hi all,
> I'm hoping that someone can clear up my confusion regarding
> special variables and threads.
>
>  My understanding is that running the following should print
>  '*my-var* is T' to standard out. I seem to think the binding
>  of *my-var* at this point will be the binding for the
>  process being created. 

I didn;t see anyone address the fundamental question so I'll give it a try.


> (defvar *my-var* nil)
>
> (defun test-it () 
>  (mp:process-run-function
>    "Test" nil
>    #'(lambda () 
>        (format #.*standard-output* "*my-var* is ~A.~%" *my-var*))))
> 
> (let ((*my-var* t))
>   (test-it))
>
> The only reason I can think of is that mp:process-run-function
> doesn't invoke the lambda form itself but puts it onto some
> sort of stack which then schedules it to run, at which point 
> my binding of *my-var* is not in effect.

That's right.  The LET etablishes a dynamic binding for *MY-VAR* in the 
thread that executes it, presumably in this case the thread of the lisp listener.

PROCESS-RUN-FUNCTION starts a new thread.  It is this new thread that executes your anonymous lambda.  The only binding of *MY-VAR* visible
to that thread is the global one.

> The only reason I can think of is that mp:process-run-function
> doesn't invoke the lambda form itself but puts it onto some
> sort of stack which then schedules it to run, at which point 
> my binding of *my-var* is not in effect.

Correct.  What else could you have imagined it doing?

Typically if one has local or dynamic state which one wants to pass 
to code which will run in a separate thread, one uses the process arguments
mecanism provided by PROCESS-RUN-FUNCTION, e.g.

(defun test-it () 
 (mp:process-run-function
   "Test" nil
   #'(lambda (*my-var*) 
       (format #.*standard-output* "*my-var* is ~A.~%" *my-var*))
    *my-var*))

Note that because the anonymous lambda sets up its own dynamic binding
for *MY-VAR*, any changes to its value made within that dynamic context will not be visible outside it, e.g. in other threads.



Updated at: 2020-12-10 08:52 UTC