{{{ > Suppose we have two threads that are both doing > >  (setq *x*
) > > where *x* is a global special variable not bound in either thread. > Is this setq atomic?  That is, can we rely on the assertion > that after both setqs have been executed, the end result is either > that *x* is set to the value of the in the first thread, > or the value of the in the second thread?   > Or do we need a lock here? The value will be one or the other of the values assigned in the two forms, but which of those two values isn't generally predictable. You won't get some bits from the first thread's value and some bits from another thread's value, or a third value or anything like that, but after a thread does: (setq *x* value) (eq *x* value) might be true or false > Same question, only this time instead of setq'ing a special, > we do > > (setf (x y) ) > > where x is a CLOS accessor function to a CLOS slot > that is declared :allocation :class.  Do we need a lock > here? It's basically the same answer: value "b" might be stored in that slot by thread B at about the time that thread A stores value "a" there; one of the threads will win, but you can't generally predict which one. Locking isn't necessary at the GC-level: some value that had been stored into the variable or class-allocation slot will be visible to the GC, and it shouldn't care if another value was there a cycle or two earlier. Locking's very often necessary at the application level, since without it it's very easy to obtain anomalous results. Suppose that an application had a couple of global variables: (defvar *number-of-requests-received* 0) (defvar *number-of-requests-completed* 0) and that whenever some thread received or completed a request it used INCF to increment the value of the global variable by 1. If we don't use locking around those INCFs, it's possible for the value of either variable to decrease when written to, and we might find that the number of completed requests exceeds the number of requests received and couldn't really trust either number. There are other, more subtle issues as well: a modern processor achieves a lot of performance gain by reordering memory accesses (sometimes doing things like combining 2 64-bit writes to adjacent memory locations into a single 128-bit write, for example). This is usually done in a way that's transparent to the program, so in the case where something is only written to by 1 thread, (progn   (setq *x* 1)   *x*) the value 1 will be returned.  That value may not really be in memory (or anywhere that triggers cache coherency protocols) yet, so the value of *x* visible to another thread running on another CPU may not match the value written until several cycles have elapsed.  (So you can't generally use a shared global value for precise synchronization between threads, unless you also force memory synchronization to occur.) }}}