I apologize for another misleading subject, as I actually have 2
distinct questions, one pertaining to threads and the other to
comments. In the future, I will make two separate posts.
First, is there any way to only comment a subsection of a line.
Sometimes I would like to just comment out part of a line and not the
whole thing. Some languages allow for the usage of /* and
*/ to do this. Is there anything similar in Lisp?
Second, I have decided to use the ACL-MP package for threads. I will
do this with ACL-COMPAT. I would like one of my threads to alter a
global variable. Is it safe to have 2 threads accessing the same
global variable - one reading and one writing. If not, please let me
know how I should avoid the issue. Thanks.
On Apr 12, 10:01 pm, dstein64 <········@gmail.com> wrote:
> First, is there any way to only comment a subsection of a line.
> Sometimes I would like to just comment out part of a line and not the
> whole thing. Some languages allow for the usage of /* and
> */ to do this. Is there anything similar in Lisp?
#| and |#
On Apr 13, 5:07 am, Brian <··············@gmail.com> wrote:
> On Apr 12, 10:01 pm, dstein64 <········@gmail.com> wrote:> First, is there any way to only comment a subsection of a line.
> > Sometimes I would like to just comment out part of a line and not the
> > whole thing. Some languages allow for the usage of /* and
> > */ to do this. Is there anything similar in Lisp?
>
> #| and |#
Yes. Moreover... /* /* */ */ does not (or at least it did not) work
in C/C++/Java etc.
#| #| |# |# DTRT.
Cheers
--
Marco
P� Sun, 13 Apr 2008 10:28:36 +0200, skrev Marco Antoniotti
<·······@gmail.com>:
>
> Yes. Moreover... /* /* */ */ does not (or at least it did not) work
> in C/C++/Java etc.
> #| #| |# |# DTRT.
>
Not portably. But most C/C++ compilers I have worked with handled this in
the expected manner.
--------------
John Thingstad
On Apr 13, 10:42 am, "John Thingstad" <·······@online.no> wrote:
> På Sun, 13 Apr 2008 10:28:36 +0200, skrev Marco Antoniotti
> <·······@gmail.com>:
>
>
>
> > Yes. Moreover... /* /* */ */ does not (or at least it did not) work
> > in C/C++/Java etc.
> > #| #| |# |# DTRT.
>
> Not portably. But most C/C++ compilers I have worked with handled this in
> the expected manner.
>
Not portably in C/C++/Java etc... you mean. #| #| |# |# works by ANSI
in CL.
--
Marco
Marco Antoniotti wrote:
> On Apr 13, 10:42 am, "John Thingstad" <·······@online.no> wrote:
>> P� Sun, 13 Apr 2008 10:28:36 +0200, skrev Marco Antoniotti
>> <·······@gmail.com>:
>>
>>
>>
>>> Yes. Moreover... /* /* */ */ does not (or at least it did not) work
>>> in C/C++/Java etc.
>>> #| #| |# |# DTRT.
>> Not portably. But most C/C++ compilers I have worked with handled this in
>> the expected manner.
>>
>
> Not portably in C/C++/Java etc... you mean. #| #| |# |# works by ANSI
> in CL.
The only portable way to nest multi-line comments in C++:
#if 0
/*
Here is a comment
*/
#endif
Yes, I did have to use compilers where /* /* */ */ confused the
compiler. I'm trying to leave it behind now. My therapist says its good
to talk about it.
Alright, so I have a thread that reads a line from a socket stream. In
many cases, the first token in this string is "ok". How come when I
read this, it seems to become COMMON-LISP-USER::OK rather than just
OK. This is interfering with my equality checks. Does this have
anything to do with the threads? Thanks.
d> Alright, so I have a thread that reads a line from a socket stream. In
d> many cases, the first token in this string is "ok". How come when I
d> read this, it seems to become COMMON-LISP-USER::OK rather than just
d> OK. This is interfering with my equality checks. Does this have
d> anything to do with the threads? Thanks.
yes, current package for thread differs from current package of REPL.
you can bind current package via (let ((*package* (find-package :whatever))
...
Thanks for all the replies. When I finally thought I understood a
little about packages and threads and a lot of other stuff, I realized
how much I don't. Anyhow, any suggestions where I can read up some
more on symbols and names... I read PCL, but would like some more
details. I was surprised to see that (equal *1* cl-user::*2*) returned
nil in the following, but this is probably due to my lack of
understanding of names and symbols. I guess that I don't really know
what kind of object 'ok is in the following. Also, I am no longer
referring to threads, just packages and symbols...
P2-PACKAGE> (defvar *1* 'ok)
*1*
P2-PACKAGE> (in-package :cl-user)
#<PACKAGE "COMMON-LISP-USER">
CL-USER> (defvar *2* 'ok)
*2*
CL-USER> (in-package :p2-package)
#<PACKAGE "P2-PACKAGE">
P2-PACKAGE> (equal *1* cl-user::*2*)
NIL
P2-PACKAGE> cl-user::*2*
COMMON-LISP-USER::OK
P2-PACKAGE> *1*
OK
P2-PACKAGE> (string= *1* cl-user::*2*)
T
P2-PACKAGE>
P� Sun, 13 Apr 2008 19:08:17 +0200, skrev dstein64 <········@gmail.com>:
> Thanks for all the replies. When I finally thought I understood a
> little about packages and threads and a lot of other stuff, I realized
> how much I don't. Anyhow, any suggestions where I can read up some
> more on symbols and names... I read PCL, but would like some more
> details. I was surprised to see that (equal *1* cl-user::*2*) returned
> nil in the following, but this is probably due to my lack of
> understanding of names and symbols. I guess that I don't really know
> what kind of object 'ok is in the following. Also, I am no longer
> referring to threads, just packages and symbols...
>
> P2-PACKAGE> (defvar *1* 'ok)
> *1*
> P2-PACKAGE> (in-package :cl-user)
> #<PACKAGE "COMMON-LISP-USER">
> CL-USER> (defvar *2* 'ok)
> *2*
> CL-USER> (in-package :p2-package)
> #<PACKAGE "P2-PACKAGE">
> P2-PACKAGE> (equal *1* cl-user::*2*)
> NIL
> P2-PACKAGE> cl-user::*2*
> COMMON-LISP-USER::OK
> P2-PACKAGE> *1*
> OK
> P2-PACKAGE> (string= *1* cl-user::*2*)
> T
> P2-PACKAGE>
CL-USER 1 > (defparameter *1* 'ok)
*1*
CL-USER 2 > (defpackage p2 (:use :cl))
#<The P2 package, 0/16 internal, 0/16 external>
CL-USER 3 > (in-package p2)
#<The P2 package, 0/16 internal, 0/16 external>
CL-USER 1 > (defparameter *1* 'ok)
*1*
CL-USER 2 > (defpackage p2 (:use :cl))
#<The P2 package, 0/16 internal, 0/16 external>
CL-USER 3 > (in-package p2)
#<The P2 package, 0/16 internal, 0/16 external>
CL-USER 1 > (defparameter *1* 'ok)
*1*
CL-USER 1 > (defparameter *1* 'ok)
*1*
P2 14 > (symbol-value *2*)
Error: The variable OK is unbound..
P2 16 > (symbol-name *2*)
"OK"
Observe that string= converts a symbol to string by applying symbol-name..
P2 17 > (equal (symbol-name cl-user::*1*) (symbol-name *2*))
T
--------------
John Thingstad
d> details. I was surprised to see that (equal *1* cl-user::*2*) returned
d> nil in the following, but this is probably due to my lack of
d> understanding of names and symbols. I guess that I don't really know
d> what kind of object 'ok is in the following.
each symbol has NAME (accessed via symbol-name) and PACKAGE (accessed via
symbol-package), package can be empty.
d> P2-PACKAGE> (defvar *1* 'ok)
d> *1*
d> P2-PACKAGE> (in-package :cl-user)
d> #<PACKAGE "COMMON-LISP-USER">
d> CL-USER> (defvar *2* 'ok)
d> *2*
*1* is p2-package::OK symbol
*2* is cl-user::OK symbol
both have name "OK", but their packages are different (that's actually what
package are made for -- to have symbols with same name which are different,
nevertheless).
so, obviously, they are two _different_ symbols, eq/eql/equal/equalp will
return NIL if you compare them.
if you print p2-package::OK when p2-package is current package, it will be
printed in "short form" as OK, but cl-user::ok will be printed with package
prefix (or not, depending on *print-escape* variable)
reader works in same way -- if it sees no prefix, it tries to intern name
into _current_ package -- first it tries to find it there, and if it's not
found, it creates new one.
thus, when you reading something and checking if it matches literal value,
you must ensure that current package is correct one.
to avoid problems of such kind, you can use ":ok" instead of "ok" -- then
symbol will be interned into keyword package regardless of current package
settings.
and one more trick -- you can import symbol from one package to another to
indicate that they agree on meaning of this symbol. so if you import BAR::OK
into package FOO, when FOO is current OK will refer to BAR::OK, but will be
printed in short form as OK.
dstein64 <········@gmail.com> writes:
> Thanks for all the replies. When I finally thought I understood a
> little about packages and threads and a lot of other stuff, I realized
> how much I don't. Anyhow, any suggestions where I can read up some
> more on symbols and names... I read PCL, but would like some more
> details.
I'm not really sure where to go for a written account with more
details. There is always the HyperSpec, but in general specification
documents are not always the best source for learning about the concepts
underlying the specification.
> I was surprised to see that (equal *1* cl-user::*2*) returned
> nil in the following, but this is probably due to my lack of
> understanding of names and symbols.
Precisely so.
> I guess that I don't really know
> what kind of object 'ok is in the following. Also, I am no longer
> referring to threads, just packages and symbols...
OK, there are several things going on here.
First of all, in the following OK is a symbol. Actually, it is two
different symbols. Symbols in Common Lisp are objects with various
characteristics and properties. They are used (among other things) as
the names of various other Lisp objects.
Symbols have the following properties (among others. This is just an
abbreviated list).
symbol-name The name of the symbol.
symbol-package The package a symbol is interned in.
symbol-value A global value.
symbol-function A global function value
...
For normal interned symbols, the combination of SYMBOL-PACKAGE and
SYMBOL-NAME uniquely identifies the symbol. Uninterned symbols will be
discussed later. Each lisp implementation maintains a mapping from the
combination of package and symbol name to symbol objects. This mapping
table is maintained by the lisp reader. This mapping data structure is
called a package. That's all a package really is. It is a data
structure that maps names to symbol objects.
When a token that matches the syntax for a symbol is encountered, the
reader looks up the name (basic the string of characters) in the current
package.* If there is already a symbol there, that symbol is returned as
the object that has been read. If there is no such object, then a new
symbol is created, stored in the package mapping table and returned.
That is the essential operation of the reader when encountering the
printed representation of a symbol.
*[Lookup is complicated somewhat by the ability of one package to IMPORT
symbols from other packages or to USE other packages -- the latter
automatically imports all of the external symbols of the package being
used. But that's a topic I'll not get into in this message.]
All right, we're ready now to look at the example.
Before this line, there were other lines to create the package named
"P2-PACKAGE" and to make it the current package.
> P2-PACKAGE> (defvar *1* 'ok)
> *1*
When the reader encounters the string "ok", it performs a couple of
actions. First of all, with the default readtable case setting, it
converts the string to uppercase: "OK". It then looks for a symbol
with the name "OK" in the current package "P2-PACKAGE". Since there
isn't any such symbol, a new one is created. The fully-qualified name
of this symbol is P2-PACKAGE::OK
[Aside: Before getting to "ok", the reader will also have encountered
"defvar" which it converted to "DEFVAR" and looked up. Since
the P2-PACKAGE uses the COMMON-LISP package by default, the
lookup succeeds for the symbol CL:DEFVAR. The reader also
creates a new symbol P2-PACKAGE::*1* when it encounters "*1".]
> P2-PACKAGE> (in-package :cl-user)
> #<PACKAGE "COMMON-LISP-USER">
Now we have changed the current package to "COMMON-LISP-USER".
> CL-USER> (defvar *2* 'ok)
> *2*
Here the reader again encounters "defvar", uppercases it to "DEFVAR" and
looks it up. Since the CL-USER package also uses the COMMON-LISP
package, looking up "DEFVAR" finds the same CL:DEFVAR symbol as the
lookup in the P2-PACKAGE. This happens because both CL-USER and
P2-PACKAGE use the same package. The reader also looks up, fails to
find and therefore creates the symbol CL-USER::*2*, when it encounters
"*2*".
Now the reader again gets the string "ok". This is converted to "OK"
and looked up in the CL-USER package. No such symbol exists. There is
a symbol with that name in the P2-PACKAGE, but that is an unrelated
symbol. Since there is no symbol named "OK" in CL-USER, a new symbol is
created with the fully qualified name of CL-USER::OK. This symbol is
different from P2-PACKAGE::OK, and from that follows the equality
failures.
(Note: I'm deliberately skipping the handling of the quote character
because it isn't relevant to symbols or packages).
> CL-USER> (in-package :p2-package)
> #<PACKAGE "P2-PACKAGE">
> P2-PACKAGE> (equal *1* cl-user::*2*)
> NIL
That's because the two symbols are different objects, and therefore not
EQ, EQL, EQUAL or even EQUALP.
> P2-PACKAGE> cl-user::*2*
> COMMON-LISP-USER::OK
> P2-PACKAGE> *1*
> OK
> P2-PACKAGE> (string= *1* cl-user::*2*)
> T
This succeeds because of special handling of so-called
string-designators in the Common Lisp language. The
STRING-... functions all operate as if the (STRING ...) function were
wrapped around their string arguments.
The STRING function, when applied to a symbol, returns the SYMBOL-NAME
of that function. So what this is really doing is the same as:
(string= (string *1*) (string cl-user::*2*))
which happens to also be the same as
(string= (symbol-name *1*) (symbol-name cl-user::*2*))
So instead of comparing symbols, it is only comparing their names. That
is a different thing.
====================
If it helps, consider the way seats are identified in theaters.
Typically the seat "numbers" are composed of a row letter and a number.
So, if you go to the Schubert theater on Broadway in New York City,
there will be a seat G12. If you go to the theater La Scala in Milan,
there will also be a seat G12. But even though those seats are both
called "G12", they are clearly not the same seat. They aren't even on
the same continent. Each theater has its own namespace for seats, and
to know which precise seat you are talking about, you need to know the
theater name as well.
It works the same way with symbols (seats) and packages (theaters). The
packages are used to provide the namespace (or context) in which to
interpret the meaning of symbol names.
====================
Uninterned symbols have NIL as their SYMBOL-PACKAGE value and thus do
not have a unique mapping from a printed representation to the object.
You therefore have to keep a reference to the actual symbol object in
order to keep using it. You cannot get a reference by reading. That is
the fundamental difference between interned and uninterned symbols.
Uninterned symbols are useful for generated constructs where you want to
guarantee that you get a fresh, unused symbol -- since there isn't any
other way to get the same symbol. This is important for avoiding name
capture in macro expansions that wrap around user-supplied code.
--
Thomas A. Russ, USC/Information Sciences Institute
dstein64 <········@gmail.com> writes:
> Alright, so I have a thread that reads a line from a socket stream. In
> many cases, the first token in this string is "ok". How come when I
> read this, it seems to become COMMON-LISP-USER::OK rather than just
> OK. This is interfering with my equality checks. Does this have
> anything to do with the threads? Thanks.
Well, for starters you can't be "reading a line", at least not using
something like READ-LINE, since that returns a string.
If you are getting a symbol, like COMMON-LISP-USER::OK, then you must be
doing some sort of Lisp like READ operation on the string. This is
probably a Bad Idea(tm), unless the contents of the socket string really
are lisp forms. In that case, READ would be appropriate. But not for
general input.
Threads have nothing to do with your problem. But packages do. Each
(interned) symbol in Lisp is identified by a combintation of a package
and symbol name. The packages form a namespace to manage the symbol
names and prevent unintended name collisions, especially with
independently developed software.
So, when you do your read operation, you are in the COMMON-LISP-USER
package, and therefore the string "OK", when encountered the Lisp reader
will be read as a symbol an interned in the COMMON-LISP-USER package.
Now, when you print it out in some other package, the package prefix has
to be printed in order to distinguish it from the symbol OK in whatever
the other package is. And yes, this causes issues with equality checks,
since the symbols are different.
There are several potential solutions, which depend to a degree on what
you are actually getting back from the socket stream. And also to what
extent you control what you are reading.
If what you are getting back is actually Lisp (or lisp-like syntax),
then you can continue to use READ to read the response. To avoid
package issues you should use a keyword for keywords like :OK, so that
they are always in the keyword package.
For other lisp items, you will want to make sure you properly bind
*PACKAGE* around the calls to the READ function.
If what you are getting back isn't lisp, then you should use something
like READ-LINE to get a string and do the appropriate interpretation of
the string in your program.
--
Thomas A. Russ, USC/Information Sciences Institute
Brian <··············@gmail.com> writes:
> On Apr 12, 10:01 pm, dstein64 <········@gmail.com> wrote:
>> First, is there any way to only comment a subsection of a line.
>> Sometimes I would like to just comment out part of a line and not the
>> whole thing. Some languages allow for the usage of /* and
>> */ to do this. Is there anything similar in Lisp?
> #| and |#
And if its to much work to insert, use these emacs functions:
(defun comment-sexp (&optional count)
"Comment out the following arg sexps"
(interactive "P")
(unless count (setq count 1))
(insert "#|")
(forward-sexp count)
(insert "|#"))
(global-set-key [(super c)] 'comment-sexp)
(defun remove-comments ()
"When point is at beginning of a hash-bar-comment, remove beginning and end comment"
(interactive)
(when (looking-at "#|")
(delete-char 2)
(save-excursion
(search-forward "|#")
(backward-delete-char 2))))
(global-set-key [(super r)] 'remove-comments)
Thank you everyone for answering all these questions. I think I just
have one more. In some of my programs I did not define my functions in
a hierarchical order. For example, I may have something like:
(defun test1 ()
(test2))
(defun test2 ()
(print "hello"))
where test2 is used by test1, but defined afterwards. The preceding
example is very trivial and can be easily avoided, but sometimes this
is not the case. Everything seems to work, but I do receive the
following message upon loading:
; in: LAMBDA NIL
; TEST2
;
; caught STYLE-WARNING:
; undefined function: TEST2
;
; caught STYLE-WARNING:
; This function is undefined:
; TEST2
;
; compilation unit finished
; caught 2 STYLE-WARNING conditions
Is there any reason that I should absolutely never do this, or make a
strong effort to avoid it? Thanks.
d> where test2 is used by test1, but defined afterwards. The preceding
d> example is very trivial and can be easily avoided, but sometimes this
d> is not the case. Everything seems to work, but I do receive the
d> following message upon loading:
it will be fine if you'll compile file and load it, because compiler is
smarter and it detects when function is later defined in same file.
i.e. you can do (load (compile-file "bugoga.lisp"))
but don't you use Emacs/SLIME? it can automatically compile-and-load
buffer -- just press C-c C-k
dstein64 <········@gmail.com> writes:
> Thank you everyone for answering all these questions. I think I just
> have one more. In some of my programs I did not define my functions in
> a hierarchical order. For example, I may have something like:
>
> (defun test1 ()
> (test2))
>
> (defun test2 ()
> (print "hello"))
>
> where test2 is used by test1, but defined afterwards. The preceding
> example is very trivial and can be easily avoided, but sometimes this
> is not the case. Everything seems to work, but I do receive the
> following message upon loading:
This is required by the standard to work, as long as the function is
defined before it is invoked.
There are several forms that work to suppress warning messages -- which
are just Style-Warnings because they don't indicate a problem with the
underlying lisp. COMPILE-FILE has been mentioned. Another possibility
is WITH-COMPILATION-UNIT. When just LOADing the source code, you can
get such warnings.
Of course you can just ignore them.
The main things (I was going to write "only", but I'm not fully certain
that I'll get them all) that need to be defined before they are
referenced in code are:
Macros (defmacro)
Struts (defstruct)
Classes that are used as method dispatch types.
--
Thomas A. Russ, USC/Information Sciences Institute
dstein64 wrote:
> Second, I have decided to use the ACL-MP package for threads. I will
> do this with ACL-COMPAT. I would like one of my threads to alter a
> global variable. Is it safe to have 2 threads accessing the same
> global variable - one reading and one writing. If not, please let me
> know how I should avoid the issue. Thanks.
Short answer: Use locking.
Long answer: This is a very complicated topic, and there are a lot of
very different approaches of dealing with this. Locking is not
necessarily the best one.
Pascal
--
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
d> Second, I have decided to use the ACL-MP package for threads. I will
d> do this with ACL-COMPAT. I would like one of my threads to alter a
d> global variable. Is it safe to have 2 threads accessing the same
d> global variable - one reading and one writing.
yes.
it would be pretty weird if simple writes to a global variable will crash
lisp, won't it?
Alex Mizrahi wrote:
> d> Second, I have decided to use the ACL-MP package for threads. I will
> d> do this with ACL-COMPAT. I would like one of my threads to alter a
> d> global variable. Is it safe to have 2 threads accessing the same
> d> global variable - one reading and one writing.
>
> yes.
> it would be pretty weird if simple writes to a global variable will crash
> lisp, won't it?
That might be a different definition of "safe" than intended by the
questioner. I think folks went around this sometime last year and
determined that in rare cases it might be possible for the reading
thread to read something other than what the writing thread had written,
with consequent hijinks. No crash, but not necessarily the behavior that
the code would seem to imply.
paul
??>> yes.
??>> it would be pretty weird if simple writes to a global variable will
??>> crash lisp, won't it?
PW> That might be a different definition of "safe" than intended by the
PW> questioner. I think folks went around this sometime last year and
PW> determined that in rare cases it might be possible for the reading
PW> thread to read something other than what the writing thread had
PW> written, with consequent hijinks. No crash, but not necessarily the
PW> behavior that the code would seem to imply.
i think these folks just had too long tongue and unhealthy fantasies..
to avoid further lengthy discussions, i'm announcing contest -- first one
who can demonstrate these "weird effects" of single global variable
assignment will recieve a prize of $10.
terms of contest:
* it should work on reasonably modern x86 processor
* reasonably mature implementation (not the one you've invented yourself)
* it is not a known bug of CPU or implementation
* by "global variable assignment" i mean (setq *variable* new-value), where
*variable* is a global special variable, no macro tricks etc.
until someone comes with demonstration, let's consider such assignment safe,
ok?
So maybe it's worth saying slightly more - if you're global variable
is, say, an array or more complicated object, then you might end up
reading the first half before a write and the second half
afterwards. Or something even more crazy!
So if you're really lucky, your program won't mind, but in practice,
this is probably bad news (in the most trivial case, imagine printing
a message which was stored in the array - you'd end up with half of
one message and half of the other coming out).
In general, you should look at what primitives the implementation
you're using provides for locking - think semaphores, mutexes
etc. But, as Pascal pointed out, there might be a much better way.
As you presumably already know, the best way is not to need this at
all, but also as you presumably already know, that's not always
possible!
Rupert
RS> So maybe it's worth saying slightly more - if you're global variable
RS> is, say, an array
global variable cannot _be_ an array. it might be contain (or reference)
array though.
RS> or more complicated object, then you might end up reading the first
RS> half before a write and the second half afterwards. Or something even
RS> more crazy!
it might be a terminology issue.
by "writting global variable" i mean something like (setq *global*
new-value)
"updating shared object" is _completely_ different thing, and indeed it
might need lock of some kind.
i totally believe that writing global variable, as in (setq *global*
new-value), is always atomic and safe in reasonably sane implementations.
RS> In general, you should look at what primitives the implementation
RS> you're using provides for locking - think semaphores, mutexes
RS> etc.
in general, one should think before trying to cargo cult something
"Alex Mizrahi" <········@users.sourceforge.net> writes:
> RS> So maybe it's worth saying slightly more - if you're global variable
> RS> is, say, an array
>
> global variable cannot _be_ an array. it might be contain (or reference)
> array though.
Sorry, I wasn't clear. You're right, of course. But the problem still
remains. After all, if one thread is performing a destructive
operation on a list while another is reading it via a map call or a
loop, say, the results could well be strange.
>
> RS> or more complicated object, then you might end up reading the first
> RS> half before a write and the second half afterwards. Or something even
> RS> more crazy!
>
> it might be a terminology issue.
> by "writting global variable" i mean something like (setq *global*
> new-value)
> "updating shared object" is _completely_ different thing, and indeed it
> might need lock of some kind.
>
Yes I understand. I don't know, however whether that's what the
original poster meant. I of course should have been clearer.
> i totally believe that writing global variable, as in (setq *global*
> new-value), is always atomic and safe in reasonably sane implementations.
>
> RS> In general, you should look at what primitives the implementation
> RS> you're using provides for locking - think semaphores, mutexes
> RS> etc.
>
> in general, one should think before trying to cargo cult something
This reference I don't understand. I see no fake aeroplanes in this
thread... But could you explain what you mean?
Rupert
RS>>> In general, you should look at what primitives the implementation
RS>>> you're using provides for locking - think semaphores, mutexes
RS>>> etc.
??>> in general, one should think before trying to cargo cult something
RS> This reference I don't understand. I see no fake aeroplanes in this
RS> thread... But could you explain what you mean?
"From time to time, the term "cargo cult" is invoked as an English language
idiom, to mean any group of people who imitate the superficial exterior of a
process or system without having any understanding of the underlying
substance."
I meant some people might just copy usage of synchronization primitives from
multithreaded program examples without actual understanding what this
synchronization is trying to solve and how it works.
so people might think that if they use mutexes they are automatically
thread-safe.
for example, we'd like to make resouce updates atomic, so reader never sees
resouce in partly-updated state.
first thing to check is if this threat is real -- ain't atomicity guaranteed
by implementation when using certain language constructs?
"Alex Mizrahi" <········@users.sourceforge.net> writes:
> RS>>> In general, you should look at what primitives the implementation
> RS>>> you're using provides for locking - think semaphores, mutexes
> RS>>> etc.
> ??>> in general, one should think before trying to cargo cult something
>
> RS> This reference I don't understand. I see no fake aeroplanes in this
> RS> thread... But could you explain what you mean?
>
> "From time to time, the term "cargo cult" is invoked as an English language
> idiom, to mean any group of people who imitate the superficial exterior of a
> process or system without having any understanding of the underlying
> substance."
>
> I meant some people might just copy usage of synchronization primitives from
> multithreaded program examples without actual understanding what this
> synchronization is trying to solve and how it works.
> so people might think that if they use mutexes they are automatically
> thread-safe.
>
> for example, we'd like to make resouce updates atomic, so reader never sees
> resouce in partly-updated state.
> first thing to check is if this threat is real -- ain't atomicity guaranteed
> by implementation when using certain language constructs?
Ah, thanks. And, yes, to say anything more that's useful to the OP or
whatever one would definitely need more info.
Incidentally, thanks for pointing out that one is safe modifying a
global variable in lisp: I'd never actually considered that it might
not do the right thing, (foolishly?) saying things like "Well that's
simple enough that it's gotta be atomic". Thanks.
Rupert
RS> Incidentally, thanks for pointing out that one is safe modifying a
RS> global variable in lisp: I'd never actually considered that it might
RS> not do the right thing, (foolishly?) saying things like "Well that's
RS> simple enough that it's gotta be atomic". Thanks.
well, it's not that simple actually -- while write itself will be just a
single atomic CPU instruction (assuming sane platform and implementation),
there might be issues due to memory ordering on SMP systems..
processors might reorder stores and loads in order to optimize performance,
and also on SMP system different processors might have different view on
memory due to CPU caches.
suppose on CPU1 we allocate fresh CONS cell and write it's address into a
global variable, while CPU2 reads variable and accesses CONS.
some architectures (e.g. Alpha) allow CPU2 to see changes in order that is
different from the order they were made.
so, CPU2 might see new value of pointer and read data from the location
pointer points to -- but that location was not updated yet and it reads
arbitrary stale junk from that location. in most nasty situation, it will
see normal CONS tags that are left over from a CONS that was allocated some
time ago and garbage-collected by now, but CAR/CDR will point into random
memory locations, so this is likely to lead to crash. in different
situation, this will be just silent data corruption..
luckily, on x86 architecture stores are guaranteed to be properly ordered,
so this isn't an issue even without special measures from implementation
developers.
as for other architectures, i think either implementors will have to insert
appropriate memory barriers to ensure everything is consistent, or write in
bold red letters in release notes that multithreaded operations are not
safe. or better drop multithreading support for such weakly ordered platform
if it's too hard to make it right.
actually you and Pascal were right when suggested to use locking if not
sure -- lock implementation will issue appropriate memory barriers on
lock/unlock to ensure right semantics of multithreaded programs.
but in some cases locking can be bad -- if locks overlap it can result in
deadlock; and if locks are too coarse or acquired too frequently, this can
result in severe overhead, and might easily defeat whole purpose of using
SMP system.
that's why it's better to investigate characteristics of a platform before
choosing particular ways to implement multithreaded safety.
dstein64 <········@gmail.com> writes:
> First, is there any way to only comment a subsection of a line.
> Sometimes I would like to just comment out part of a line and not the
> whole thing. Some languages allow for the usage of /* and
> */ to do this. Is there anything similar in Lisp?
During development, if I want to "comment out" a single s-expression,
I'll sometimes just put a #+ignore before it.