From: Pascal Costanza
Subject: Setting specials for the rest of a computation
Date: 
Message-ID: <4vv51rF1dbfeaU1@mid.individual.net>
Hi,

Assume you want to set a special variable to change it for the rest of a 
computation, but you only want to do this for the current thread.

For example, you want to say (setf *print-base* 16), such that all 
subsequent number print operations are performed with base 16, but I 
_don't_ want to affect other currently executing threads with this 
assignment.

(let ((*print-base* 16)) ...) doesn't work for what I want to do here, 
because after return from the let body, the old value of *print-base* is 
restored. However, I would like to change *print-base* for the _entire_ 
subsequent computation.

Any idea how I could achieve this? In the CL implementations with 
multithreading, are there known solutions for this? Maybe even functions 
or macros to help me here?

Any strong opinions why this might be a bad idea in the first place?

Any hints are appreciated.


Thanks in advance,
Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/

From: ··@codeartist.org
Subject: Re: Setting specials for the rest of a computation
Date: 
Message-ID: <1167756190.758938.297810@42g2000cwt.googlegroups.com>
Pascal Costanza schrieb:

> (let ((*print-base* 16)) ...) doesn't work for what I want to do here,
> because after return from the let body, the old value of *print-base* is
> restored. However, I would like to change *print-base* for the _entire_
> subsequent computation.

Hm... so (mp:process-run-function 'test () (lambda () (let
((*print-base* 16)) ..)))
is not what you want. (Even when you might wrap such a closure around
the real function?)

(defun my-process-run-function (name keywords function &rest args)
  (mp:process-run-function name keywords
      (lambda () (let ((*print-base* 16)) (apply function args)))))

> Any idea how I could achieve this? In the CL implementations with
> multithreading, are there known solutions for this? Maybe even functions
> or macros to help me here?

For LispWorks perhaps mp:*process-initial-bindings* ?
I think ACL has a similar concept.

ciao,
Jochen
From: Kaz Kylheku
Subject: Re: Setting specials for the rest of a computation
Date: 
Message-ID: <1167758865.460226.172340@n51g2000cwc.googlegroups.com>
On Jan 2, 5:29 am, Pascal Costanza <····@p-cos.net> wrote:
> (let ((*print-base* 16)) ...) doesn't work for what I want to do here,
> because after return from the let body, the old value of *print-base* is
> restored. However, I would like to change *print-base* for the _entire_
> subsequent computation.
>
> Any idea how I could achieve this? In the CL implementations with
> multithreading, are there known solutions for this? Maybe even functions
> or macros to help me here?

Yes do both LET and SETF.

Set up the dynamic binding using a broader dynamic contour, one which
includes all of the subsequent computation that you care about.

This might mean, for instance, placing the LET right inside the very
first function that the thread executes.

This ensures that you have a thread-local dynamic binding for the
variable throughout that contour.

Then you just assign to the variable when you need to.
From: George Neuner
Subject: Re: Setting specials for the rest of a computation
Date: 
Message-ID: <aq3lp2t4qh3lnuntcbf6mui0f3oj1ur071@4ax.com>
On Tue, 02 Jan 2007 14:29:31 +0100, Pascal Costanza <··@p-cos.net>
wrote:

>Assume you want to set a special variable to change it for the rest of a 
>computation, but you only want to do this for the current thread.
>
>For example, you want to say (setf *print-base* 16), such that all 
>subsequent number print operations are performed with base 16, but I 
>_don't_ want to affect other currently executing threads with this 
>assignment.
>
>(let ((*print-base* 16)) ...) doesn't work for what I want to do here, 
>because after return from the let body, the old value of *print-base* is 
>restored. However, I would like to change *print-base* for the _entire_ 
>subsequent computation.
>
>Any idea how I could achieve this? In the CL implementations with 
>multithreading, are there known solutions for this? Maybe even functions 
>or macros to help me here?

Most threaded Lisps only share the outermost context ... once a thread
rebinds a special it has it's own copy.  So binding *print-base* in
your thread won't affect other currently running threads.  However, it
_may_ affect new threads started under the local binding - but ideally
the new thread should start with its own copy of *print-base* because
the current binding is not top level.

Which suggests that you could simply run the rest of the computation
in a new thread started under the local binding.  Alternatively you
could just rebind *print-base* at the [logical] beginning of your
thread and then do whatever you want with it.  


>Any strong opinions why this might be a bad idea in the first place?

As long as you don't alter the top level binding - which may affect
unrelated threads - I don't see any problems.

George
--
for email reply remove "/" from address
From: Rainer Joswig
Subject: Re: Setting specials for the rest of a computation
Date: 
Message-ID: <C1C07093.69B39%joswig@lisp.de>
Am 02.01.2007 14:29 Uhr schrieb "Pascal Costanza" unter <··@p-cos.net> in
···············@mid.individual.net:

> Hi,
> 
> Assume you want to set a special variable to change it for the rest of a
> computation, but you only want to do this for the current thread.
> 
> For example, you want to say (setf *print-base* 16), such that all
> subsequent number print operations are performed with base 16, but I
> _don't_ want to affect other currently executing threads with this
> assignment.
> 
> (let ((*print-base* 16)) ...) doesn't work for what I want to do here,
> because after return from the let body, the old value of *print-base* is
> restored. However, I would like to change *print-base* for the _entire_
> subsequent computation.
> 
> Any idea how I could achieve this? In the CL implementations with
> multithreading, are there known solutions for this? Maybe even functions
> or macros to help me here?
> 
> Any strong opinions why this might be a bad idea in the first place?
> 
> Any hints are appreciated.
> 
> 
> Thanks in advance,
> Pascal

That is an interesting question which really opens cans of worms. ;-)


http://www.franz.com/support/documentation/8.0/doc/multiprocessing.htm#dynam
ic-environments-1

http://www.lispworks.com/documentation/lw50/LWRM/html/lwref-399.htm#pgfId-88
6570
From: Marcin 'Qrczak' Kowalczyk
Subject: Re: Setting specials for the rest of a computation
Date: 
Message-ID: <87y7olrwca.fsf@qrnik.zagroda>
Rainer Joswig <······@lisp.de> writes:

> That is an interesting question which really opens cans of worms. ;-)
>
> http://www.franz.com/support/documentation/8.0/doc/multiprocessing.htm#dynamic-environments-1
>
> http://www.lispworks.com/documentation/lw50/LWRM/html/lwref-399.htm#pgfId-886570

I believe it would have been better to just let newly created threads
inherit dynamic bindings from the point of their creation.

-- 
   __("<         Marcin Kowalczyk
   \__/       ······@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
From: Kaz Kylheku
Subject: Re: Setting specials for the rest of a computation
Date: 
Message-ID: <1167772307.436404.302160@k21g2000cwa.googlegroups.com>
Marcin 'Qrczak' Kowalczyk wrote:
> Rainer Joswig <······@lisp.de> writes:
>
> > That is an interesting question which really opens cans of worms. ;-)
> >
> > http://www.franz.com/support/documentation/8.0/doc/multiprocessing.htm#dynamic-environments-1
> >
> > http://www.lispworks.com/documentation/lw50/LWRM/html/lwref-399.htm#pgfId-886570
>
> I believe it would have been better to just let newly created threads
> inherit dynamic bindings from the point of their creation.

I had a chance to experiment with these types of design choices on my
last job, where I whipped up a Lisp dialect for running automated tests
on a cell phone.

This dialect had no distinction between lexical and dynamic variables.
It didn't need to, because I implemented dynamic closures.

As an aside, one thing I discovered is that full dynamic closures
capture too much! You lose the ability to override a dynamic variable
around a funcall, because the closure already captured that same
variable dynamically, without that being the programmer's intent. So I
implemented a hack to actually make the capture artificially stop at a
lexical contour. To do that, I actually had a run time boolean property
in the enviornment frame to designate it as being the evaluation frame
of a top-level form, not enclosed by any other form. The closure
capture routine would stop copying frames when it hit that flag.

In my dialect, I experimented with inheriting the parent thread's
dynamic environment (the parent being the thread which created the
given thread). This was actually an interesting choice. One problem
with it is that the variables in question are no longer thread
specific. The new threads are using the same bindings as the parent.
This now requires the programmer to defend it when it's unwanted, and
leads to unintended consequences when it's forgotten. A thread can
normally guard against dynamic variable interference from other threads
by rebinding those variables, which is a nice assurance. Under this
design decision, a thread is at risk of data races over dynamic
variables from any of the threads which it creates.

What you might want would be to copy all of the parent's bindings: for
all dynamic variables which are bound in the parent thread, take their
values only, and install them into fresh bindings. For all other
dynamic variables (i.e. ones with top-level bindings only), just take
them as they are.

This would give you a nice argument passing mechanism for thread
parameters also. You could bind a bunch of different context things to
dynamic variables and then create a thread.  Then assign new values to
them, create another thread, etc.
From: Marcin 'Qrczak' Kowalczyk
Subject: Re: Setting specials for the rest of a computation
Date: 
Message-ID: <87fyatf0x9.fsf@qrnik.zagroda>
"Kaz Kylheku" <········@gmail.com> writes:

> What you might want would be to copy all of the parent's bindings:
> for all dynamic variables which are bound in the parent thread, take
> their values only, and install them into fresh bindings. For all
> other dynamic variables (i.e. ones with top-level bindings only),
> just take them as they are.

I disagree: the thread should share the bindings, so the semantics
stays the same no matter whether the inherited binding is global or
not.

OTOH well written code should avoid SETFing special variables, unless
it has just established a local binding for them. This guards against
data races with newly created threads.

-- 
   __("<         Marcin Kowalczyk
   \__/       ······@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
From: Rainer Joswig
Subject: Re: Setting specials for the rest of a computation
Date: 
Message-ID: <joswig-A30DCA.22004002012007@news-europe.giganews.com>
In article <··············@qrnik.zagroda>,
 Marcin 'Qrczak' Kowalczyk <······@knm.org.pl> wrote:

> Rainer Joswig <······@lisp.de> writes:
> 
> > That is an interesting question which really opens cans of worms. ;-)
> >
> > http://www.franz.com/support/documentation/8.0/doc/multiprocessing.htm#dynam
> > ic-environments-1
> >
> > http://www.lispworks.com/documentation/lw50/LWRM/html/lwref-399.htm#pgfId-88
> > 6570
> 
> I believe it would have been better to just let newly created threads
> inherit dynamic bindings from the point of their creation.

What makes you 'believe' that?
From: Marcin 'Qrczak' Kowalczyk
Subject: Re: Setting specials for the rest of a computation
Date: 
Message-ID: <87k605f16y.fsf@qrnik.zagroda>
Rainer Joswig <······@lisp.de> writes:

>> I believe it would have been better to just let newly created threads
>> inherit dynamic bindings from the point of their creation.
>
> What makes you 'believe' that?

A concurrent MAP has the same semantics as the regular MAP wrt. special
bindings.

The global bindings of a special variable aren't treated specially
(no pun intended), i.e. executing a program in the scope of a LET
which binds a special variable has the same semantics as executing
it in the environment where this variable has a global binding with
the same initial value, even if it uses threads.

-- 
   __("<         Marcin Kowalczyk
   \__/       ······@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
From: Pascal Costanza
Subject: Re: Setting specials for the rest of a computation
Date: 
Message-ID: <502c49F1ck5bgU1@mid.individual.net>
Thanks to all those who have responded (Jochen, Goerge, Kaz, Rainer and 
Marcin). This was very helpful!


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/