Sam Steingold | 2 Nov 2009 04:12
Picon

Re: mt question/problem

> * Don Cohen <qba-fbheprsbetr-kkm <at> vfvf.pf3-vap.pbz> [2009-11-01 17:41:30 -0800]:
>
> I may have asked something like this before, but ...
>
> (mt:make-thread 
>  (lambda () 
>    (format t "testing: ~a" 
>         (multiple-value-list (ignore-errors (list *print-pretty* c))))) 
>  :name (format nil "foo" ) 
>  :initial-bindings 
>  (print (loop for x on 
>                   (list 'c 'c) 
>                   by #'cddr collect 
>                   (cons (car x) (list 'quote (cadr x)))))) 
>  
> ((C QUOTE C))  
> #<THREAD "foo"> 
> Break 2 [11]> testing:  
> (NIL 
>  :LAMBDA: variable C has no value 
> )
>
> Why is the variable C unbound in the thread when the initial bindings
> list seems to contain a value for it?

because initial-bindings are for global specials:

[1]> (defparameter c 23)
C
[2]> (mt:make-thread 
(Continue reading)

Don Cohen | 2 Nov 2009 18:45
Favicon

Re: mt question/problem

Sam Steingold writes:
 > > * Don Cohen <qba-fbheprsbetr-kkm <at> vfvf.pf3-vap.pbz> [2009-11-01 17:41:30 -0800]:
 > > Why is the variable C unbound in the thread when the initial bindings
 > > list seems to contain a value for it?
 > because initial-bindings are for global specials:
I don't see anything about this in the doc.
What's the difference between a global special and any other kind?
How does :initial-bindings compare to something like
(let ((vars '(a b c))(vals (list a b c)))
 (mt:make-thread 
  (lambda ()
   (progv vars vals ...))))

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay 
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
clisp-devel mailing list
clisp-devel <at> lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/clisp-devel

Vladimir Tzankov | 2 Nov 2009 20:14
Picon

Re: mt question/problem

On 11/2/09, Don Cohen <don-sourceforge-xxz <at> isis.cs3-inc.com> wrote:
> Sam Steingold writes:
>  > > * Don Cohen <qba-fbheprsbetr-kkm <at> vfvf.pf3-vap.pbz> [2009-11-01 17:41:30
> -0800]:
>  > > Why is the variable C unbound in the thread when the initial bindings
>  > > list seems to contain a value for it?
>  > because initial-bindings are for global specials:
> I don't see anything about this in the doc.
> What's the difference between a global special and any other kind?

defparameter, defvar and proclaimed specials cause per value cell to
be allocated for symbols. Special variables may have different
bindings in different threads.

> How does :initial-bindings compare to something like
> (let ((vars '(a b c))(vals (list a b c)))
>  (mt:make-thread
>   (lambda ()
>    (progv vars vals ...))))

If A, B and C are not special variables they will not have per thread
allocated value cells - bindings that progv will establish will be
shared between all threads (values of A,B and C in all threads will be
the same).

Note also that vars and vals values will be shared between two threads
(in case above it's not important) - in order to avoid this (let
((vars vars) (vals vals)) (mt:make-thread ...)) may be used.

------------------------------------------------------------------------------
(Continue reading)

Don Cohen | 2 Nov 2009 23:16
Favicon

Re: mt question/problem


I begin to understand - this all seems to be related to the
implementation choice to use a "shallow binding" scheme.

It seems to me that the "deep binding" scheme has the "obviously
correct" semantics (meaning, what seems obvious to me, but of course
the semantics of lisp was never really defined for multiple threads).
Shallow binding was a clever optimization of deep binding that works
only in a single threaded environment.  

I think you're now trying to use shallow binding but changing the
semantics of special variables.  This is also not entirely clear from
the doc.

 32.5.2.2. Special Variable Values
 Every dynamic variable has a global value that can be shared across
 all MT:THREADs.
 Bindings of dynamic variables (via LET/LET*/MULTIPLE-VALUE-BIND) are
 local to MT:THREADs, i.e. every SYMBOL has a different value cell in
 each MT:THREAD. MT:SYMBOL-VALUE-THREAD can be used to inspect and
 modify these thread local bindings.

Here I would have expected 
 (let (c) (declare (special c)) (foo))
to qualify under the above "Bindings of dynamic variables".

One might argue that the very fact that CLHS defines symbol-value
seems to require something like shallow binding, but it strikes me
that it might also be consistent with CLHS to make symbol-value depend
implicitly on (current-thread).  And this would better preserve the
(Continue reading)

Vladimir Tzankov | 3 Nov 2009 13:00
Picon

Re: mt question/problem

On 11/3/09, Don Cohen <don-sourceforge-xxz <at> isis.cs3-inc.com> wrote:
> So defvar and defparameter create what you call "global" specials?
> But (declare (special ...)) does not, right?
> I'm now guessing that (let (x)(declare (special x))...) uses "the
> global" value cell in the the symbol x rather than a cell for x in the
> current thread.  This violates my intuition/understanding of what
> special variables are all about.  Can you see any justification for
> such semantics other than ease of implementation?

Actually it worked (almost) the way you describe until 2009-10-25 when
I changed it in cvs. Now rethinking it - looks I wrongly removed it.
Every special declaration should allocate per thread value cell for
the symbol (if it does not have already).
Sam?

>  > On 11/2/09, Don Cohen <don-sourceforge-xxz <at> isis.cs3-inc.com> wrote:
>  > > How does :initial-bindings compare to something like
>  > > (let ((vars '(a b c))(vals (list a b c)))
>  > >  (mt:make-thread
>  > >   (lambda ()
>  > >    (progv vars vals ...))))
>  >
>  > The main difference is that forms in initial-bindings are eval-ed in
>  > the context of newly created thread.
> Whoa!!  This is even more unexpected!  Was that in the doc somewhere?

http://clisp.org/impnotes/mt.html#make-thread

> It seems to me that the current design makes it unnecessarily
> difficult to pass arguments to the new thread.  I'd really like to do
(Continue reading)

Sam Steingold | 3 Nov 2009 16:51
Picon

Re: mt question/problem

Vladimir Tzankov wrote:
> On 11/3/09, Don Cohen <don-sourceforge-xxz <at> isis.cs3-inc.com> wrote:
>> So defvar and defparameter create what you call "global" specials?
>> But (declare (special ...)) does not, right?
>> I'm now guessing that (let (x)(declare (special x))...) uses "the
>> global" value cell in the the symbol x rather than a cell for x in the
>> current thread.  This violates my intuition/understanding of what
>> special variables are all about.  Can you see any justification for
>> such semantics other than ease of implementation?
> 
> Actually it worked (almost) the way you describe until 2009-10-25 when
> I changed it in cvs. Now rethinking it - looks I wrongly removed it.
> Every special declaration should allocate per thread value cell for
> the symbol (if it does not have already).

A vast majority of special variables a global, so this is not terribly important.
However, if a function FOO depends on a special variable BAR and we do

(make-thread (lambda () (let ((bar 1)) (foo))))

and

(make-thread #'foo)

At the same time, them we should NOT have a race, i.e., the behavior of the 
second thread should not depend on whether its FOO happened to be executed 
while the first thread bound BAR to 1.

So, yes, you are right, a special declaration should only modify the 
thread-local value cell.
(Continue reading)

Vladimir Tzankov | 3 Nov 2009 17:07
Picon

Re: mt question/problem

On 11/3/09, Sam Steingold <sds <at> gnu.org> wrote:
>>> Most of the other things in *DEFAULT-SPECIAL-BINDINGS* seem
>>> unnecessary or worse, e.g., *print-base* - shouldn't the default be
>>> whatever I set the "global" value to?
>>
>> We may use symbols global values, creating thread bindings or some
>> "safe" values - like now. First option looks most natural.
>
> I am highly ambivalent.
> What if *print-base* is set (or bound) in one thread while another thread is
> writing a large file?
> If all threads use the same global value, part of the file will be written
> with one base and the rest with the other.

Every thread on it's creation will bind *print-base* (as it is now) in
order to prevent such cases.
The question is what should be the initial value - now it is 10, but
we may use *print-base* global value instead. In
*default-special-bindings we will have:
(*print-base* . (mt:symbol-value-thread '*print-base* nil))

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay 
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
clisp-devel mailing list
clisp-devel <at> lists.sourceforge.net
(Continue reading)

Sam Steingold | 3 Nov 2009 17:12
Picon

Re: mt question/problem

Vladimir Tzankov wrote:
> On 11/3/09, Sam Steingold <sds <at> gnu.org> wrote:
>>>> Most of the other things in *DEFAULT-SPECIAL-BINDINGS* seem
>>>> unnecessary or worse, e.g., *print-base* - shouldn't the default be
>>>> whatever I set the "global" value to?
>>> We may use symbols global values, creating thread bindings or some
>>> "safe" values - like now. First option looks most natural.
>> I am highly ambivalent.
>> What if *print-base* is set (or bound) in one thread while another thread is
>> writing a large file?
>> If all threads use the same global value, part of the file will be written
>> with one base and the rest with the other.
> 
> Every thread on it's creation will bind *print-base* (as it is now) in
> order to prevent such cases.

precisely my point.

> The question is what should be the initial value - now it is 10, but
> we may use *print-base* global value instead. In
> *default-special-bindings we will have:
> (*print-base* . (mt:symbol-value-thread '*print-base* nil))

can we just use

(*print-base* . *print-base*)

(and the same for all the other variables)?

------------------------------------------------------------------------------
(Continue reading)

Vladimir Tzankov | 3 Nov 2009 18:04
Picon

Re: mt question/problem

On 11/3/09, Sam Steingold <sds <at> gnu.org> wrote:
>> *default-special-bindings we will have:
>> (*print-base* . (mt:symbol-value-thread '*print-base* nil))
>
> can we just use
>
> (*print-base* . *print-base*)
of course!

> (and the same for all the other variables)?
All of them?
What about *gensym-counter* - I am worried that it's possible two
threads to generate same symbol?

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay 
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
clisp-devel mailing list
clisp-devel <at> lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/clisp-devel

Sam Steingold | 3 Nov 2009 18:27
Picon

Re: mt question/problem

Vladimir Tzankov wrote:
> On 11/3/09, Sam Steingold <sds <at> gnu.org> wrote:
>>> *default-special-bindings we will have:
>>> (*print-base* . (mt:symbol-value-thread '*print-base* nil))
>> can we just use
>> (*print-base* . *print-base*)
> of course!

Good.
You would also need to replace (copy-readtable nil) with (copy-readtable) so 
that *readtable* is also inherited.

>> (and the same for all the other variables)?
> All of them?
> What about *gensym-counter* - I am worried that it's possible two
> threads to generate same symbol?

First of all, GENSYM always creates a new uninterned symbol, so even if two 
threads have the same counters and create symbols with the same names, they 
would still be different symbols, so there is no problem here.
Technically, one can replace all calls to GENSYM in macros with (MAKE-SYMBOL 
"") and everything would still work just fine. The only reason we use GENSYM is 
for visual debugging of macroexpansions.
Second, I see no reason to bound *GENSYM-COUNTER* at all. Let it always be the 
global value, as I explained, there is no problem with sharing.

Sam.

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
(Continue reading)

Don Cohen | 3 Nov 2009 22:41
Favicon

Re: mt question/problem

Vladimir Tzankov writes:

 > Actually it worked (almost) the way you describe until 2009-10-25 when
 > I changed it in cvs. Now rethinking it - looks I wrongly removed it.
 > Every special declaration should allocate per thread value cell for
 > the symbol (if it does not have already).
I think above means (but I want to verify) that you plan to change
things so that all bindings of special vars are -per-thread.
Let me know when you think it's done and I'll try removing the defvar
I had to add.

 > > So far I'm having trouble seeing when/why it's useful to do that
 > > evaluation in the new thread.
 > Whenever (current-thread) value or some mutex ownership involved in
 > evaluation is important.
Why not 
 (mt:make-thread (lambda () (let ((*th* (mt:current-thread))) ...)))
Or for that matter,
 (mt:make-thread (lambda () (let ((*read-base* *read-base*)) ...)))

These seem related to this:
 > (defun new-thread (function &rest args)
 >    (mt:make-thread (lambda () (apply function args))))
in that it feels to me like you're going out of your way (adding
initial bindings arg) to make it easy to do things that I'll rarely
want to do while failing to make it easy to do things that I'll
normally want to do.  I'd expect it to be relatively rare that
programs even mention things in *default-special-bindings*, let alone
change them or rely on having different values in different threads,
whereas one will almost always want to pass arguments to the functions
(Continue reading)

Don Cohen | 3 Nov 2009 22:46
Favicon

[sorry for my failure to edit the mail headers!!]


which is the cause of multiple copies of the last message

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay 
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
clisp-devel mailing list
clisp-devel <at> lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/clisp-devel

Vladimir Tzankov | 5 Nov 2009 20:45
Picon

Re: mt question/problem

On 11/3/09, Don Cohen <don-sourceforge-xxz <at> isis.cs3-inc.com> wrote:
> in that it feels to me like you're going out of your way (adding
> initial bindings arg) to make it easy to do things that I'll rarely
> want to do while failing to make it easy to do things that I'll
> normally want to do.  I'd expect it to be relatively rare that
> programs even mention things in *default-special-bindings*, let alone
> change them or rely on having different values in different threads,
> whereas one will almost always want to pass arguments to the functions
> to be called in new threads.

initial-bindings are not meant as mechanism for passing parameters to
thread function.
I do not expect many people to use them but they serve as easy way to
customize (or isolate) dynamic environments of threads.

>  > > What if *print-base* is set (or bound) in one thread while another
>  > > thread is writing a large file?
>  > > If all threads use the same global value, part of the file will be
> written
>  > > with one base and the rest with the other.
> If it's bound, the proposed (what I called correct) behavior of
> binding it only for the thread will solve this problem.
> If it's set and not bound in the writing thread, as I propose by
> default, then the file will indeed be strange - but this is no
> different from all the other global state that could be used by one
> thread and altered by another.  Worrying about such things falls
> within the normal job description of a programmer.

Sure, but programmers somehow do not want to worry about such things.
I guess that's the reason most implementations provide such feature.
(Continue reading)

Vladimir Tzankov | 2 Nov 2009 21:09
Picon

Re: mt question/problem

On 11/2/09, Don Cohen <don-sourceforge-xxz <at> isis.cs3-inc.com> wrote:
> How does :initial-bindings compare to something like
> (let ((vars '(a b c))(vals (list a b c)))
>  (mt:make-thread
>   (lambda ()
>    (progv vars vals ...))))

The main difference is that forms in initial-bindings are eval-ed in
the context of newly created thread. Thus any reference to thread
specific data (mt:current-thread, mutex ownership change, deferred
interrupts ..) are specific to new thread. Evaluation of these forms
is performed before just before funcall-ing the thread lambda.

Main purpose of initial-bindings is to perform initialization of some
global data that should not be shared between threads -
*random-state*, *readtable*, *defer-interrupts*, etc - not for passing
"arguments" to thread function - see *DEFAULT-SPECIAL-BINDINGS* in
threads.lisp.
When you use initial-bindings it's best to cons your specific data in
front of *DEFAULT-SPECIAL-BINDINGS* or copy and modify it to fit your
needs.

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay 
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
clisp-devel mailing list
(Continue reading)


Gmane