SBCL supports a fairly low-level threading interface that maps onto
the host operating system's concept of threads or lightweight
processes. This means that threads may take advantage of hardware
-multiprocessing on machines that have more than one CPU, but it does
+multiprocessing on machines that have more than one CPU, but it does
not allow Lisp control of the scheduler. This is found in the
SB-THREAD package.
-This requires x86/x86-64 and Linux kernel 2.6 or systems with NPTL
-backports.
+Threads are part of the default build on x86[-64] Linux only.
+
+They are also experimentally supported on: x86[-64] Darwin (Mac OS X),
+x86[-64] FreeBSD, x86 SunOS (Solaris), and PPC Linux. On these platforms
+threads must be explicitly enabled at build-time, see @file{INSTALL} for
+directions.
@menu
* Threading basics::
* Special Variables::
+* Atomic Operations::
* Mutex Support::
+* Semaphores::
* Waitqueue/condition variables::
+* Barriers::
* Sessions/Debugging::
-* Implementation (Linux x86)::
+* Foreign threads::
+* Implementation (Linux x86/x86-64)::
@end menu
@node Threading basics
(make-thread (lambda () (write-line "Hello, world")))
@end lisp
+@subsection Thread Objects
+
@include struct-sb-thread-thread.texinfo
@include var-sb-thread-star-current-thread-star.texinfo
-@include fun-sb-thread-make-thread.texinfo
-@include fun-sb-thread-thread-alive-p.texinfo
@include fun-sb-thread-list-all-threads.texinfo
-@include condition-sb-thread-interrupt-thread-error.texinfo
-@include fun-sb-thread-interrupt-thread-error-thread.texinfo
-@include fun-sb-thread-interrupt-thread-error-errno.texinfo
+@include fun-sb-thread-thread-alive-p.texinfo
+@include fun-sb-thread-thread-name.texinfo
+@include fun-sb-thread-main-thread-p.texinfo
+@include fun-sb-thread-main-thread.texinfo
+
+@subsection Making, Returning From, Joining, and Yielding Threads
+
+@include fun-sb-thread-make-thread.texinfo
+@include macro-sb-thread-return-from-thread.texinfo
+@include fun-sb-thread-abort-thread.texinfo
+@include fun-sb-thread-join-thread.texinfo
+@include fun-sb-thread-thread-yield.texinfo
+
+@subsection Asynchronous Operations
+
@include fun-sb-thread-interrupt-thread.texinfo
@include fun-sb-thread-terminate-thread.texinfo
+@subsection Miscellaneous Operations
+
+@include fun-sb-thread-symbol-value-in-thread.texinfo
+
+@subsection Error Conditions
+
+@include condition-sb-thread-thread-error.texinfo
+@include fun-sb-thread-thread-error-thread.texinfo
+
+@c @include condition-sb-thread-symbol-value-in-thread-error.texinfo
+@include condition-sb-thread-interrupt-thread-error.texinfo
+@include condition-sb-thread-join-thread-error.texinfo
+
@node Special Variables
@comment node-name, next, previous, up
@section Special Variables
The interaction of special variables with multiple threads is mostly
-as one would expect, but users of other Lisps are warned that the
-behaviour of locally bound specials differs in places from what they
-may expect.
+as one would expect, with behaviour very similar to other
+implementations.
@itemize
-@item
+@item
global special values are visible across all threads;
@item
bindings (e.g. using LET) are local to the thread;
@item
-initial values in a new thread are taken from the thread that created it.
+threads do not inherit dynamic bindings from the parent thread
@end itemize
The last point means that
(sb-thread:make-thread (lambda () (print *x*))))
@end lisp
-prints @code{1}.
-
+prints @code{0} and not @code{1} as of 0.9.6.
+
+@node Atomic Operations
+@comment node-name, next, previous, up
+@section Atomic Operations
+
+Following atomic operations are particularly useful for implementing
+lockless algorithms.
+
+@include macro-sb-ext-atomic-decf.texinfo
+@include macro-sb-ext-atomic-incf.texinfo
+@include macro-sb-ext-atomic-pop.texinfo
+@include macro-sb-ext-atomic-push.texinfo
+@include macro-sb-ext-atomic-update.texinfo
+@include macro-sb-ext-compare-and-swap.texinfo
+
+@unnumberedsubsec CAS Protocol
+
+Our @code{compare-and-swap} is user-extensible using a protocol
+similar to @code{setf}, allowing users to add CAS support to new
+places via e.g. @code{defcas}.
+
+At the same time, new atomic operations can be built on top of CAS
+using @code{get-cas-expansion}. See @code{atomic-update},
+@code{atomic-push}, and €@code{atomic-pop} for example of how to do
+this.
+
+@include macro-sb-ext-cas.texinfo
+@include macro-sb-ext-define-cas-expander.texinfo
+@include macro-sb-ext-defcas.texinfo
+@include fun-sb-ext-get-cas-expansion.texinfo
+
@node Mutex Support
@comment node-name, next, previous, up
@section Mutex Support
will be made to wait until it's free. Threads are woken in the order
that they go to sleep.
-There isn't a timeout on mutex acquisition, but the usual WITH-TIMEOUT
-macro (which throws a TIMEOUT condition after n seconds) can be used
-if you want a bounded wait.
-
@lisp
(defpackage :demo (:use "CL" "SB-THREAD" "SB-EXT"))
(with-mutex (*a-mutex*)
(format t "Thread ~A got the lock~%" *current-thread*)
(sleep (random 5)))
- (format t "Thread ~A dropped lock, dying now~%" *current-thread*)))
+ (format t "Thread ~A dropped lock, dying now~%" *current-thread*))
(make-thread #'thread-fn)
(make-thread #'thread-fn)
@end lisp
@include struct-sb-thread-mutex.texinfo
+
+@include macro-sb-thread-with-mutex.texinfo
+@include macro-sb-thread-with-recursive-lock.texinfo
+
@include fun-sb-thread-make-mutex.texinfo
@include fun-sb-thread-mutex-name.texinfo
+@include fun-sb-thread-mutex-owner.texinfo
@include fun-sb-thread-mutex-value.texinfo
-@include fun-sb-thread-get-mutex.texinfo
+@include fun-sb-thread-grab-mutex.texinfo
@include fun-sb-thread-release-mutex.texinfo
-@include macro-sb-thread-with-mutex.texinfo
-@include macro-sb-thread-with-recursive-lock.texinfo
+
+@node Semaphores
+@comment node-name, next, previous, up
+@section Semaphores
+
+Semaphores are among other things useful for keeping track of a
+countable resource, e.g. messages in a queue, and sleep when the
+resource is exhausted.
+
+@include struct-sb-thread-semaphore.texinfo
+@include fun-sb-thread-make-semaphore.texinfo
+@include fun-sb-thread-signal-semaphore.texinfo
+@include fun-sb-thread-wait-on-semaphore.texinfo
+@include fun-sb-thread-try-semaphore.texinfo
+@include fun-sb-thread-semaphore-count.texinfo
+@include fun-sb-thread-semaphore-name.texinfo
+
+@include struct-sb-thread-semaphore-notification.texinfo
+@include fun-sb-thread-make-semaphore-notification.texinfo
+@include fun-sb-thread-semaphore-notification-status.texinfo
+@include fun-sb-thread-clear-semaphore-notification.texinfo
@node Waitqueue/condition variables
@comment node-name, next, previous, up
There are three components:
@itemize
-@item
+@item
the condition itself (not represented in code)
-@item
-the condition variable (a.k.a waitqueue) which proxies for it
+@item
+the condition variable (a.k.a. waitqueue) which proxies for it
-@item
-a lock to hold while testing the condition
+@item
+a lock to hold while testing the condition
@end itemize
Important stuff to be aware of:
@itemize
-@item
+@item
when calling condition-wait, you must hold the mutex. condition-wait
will drop the mutex while it waits, and obtain it again before
returning for whatever reason;
-@item
+@item
likewise, you must be holding the mutex around calls to
condition-notify;
-@item
+@item
a process may return from condition-wait in several circumstances: it
is not guaranteed that the underlying condition has become true. You
must check that the resource is ready for whatever you want to do to
(unless *buffer* (return))
(let ((head (car *buffer*)))
(setf *buffer* (cdr *buffer*))
- (format t "reader ~A woke, read ~A~%"
+ (format t "reader ~A woke, read ~A~%"
*current-thread* head))))))
(defun writer ()
(sleep (random 5))
(with-mutex (*buffer-lock*)
(let ((el (intern
- (string (code-char
+ (string (code-char
(+ (char-code #\A) (random 26)))))))
(setf *buffer* (cons el *buffer*)))
(condition-notify *buffer-queue*))))
(make-thread #'writer)
(make-thread #'reader)
-(make-thread #'reader)
+(make-thread #'reader)
@end lisp
@include struct-sb-thread-waitqueue.texinfo
@include fun-sb-thread-condition-notify.texinfo
@include fun-sb-thread-condition-broadcast.texinfo
+@node Barriers
+@comment node-name, next, previous, up
+@section Barriers
+
+These are based on the Linux kernel barrier design, which is in turn
+based on the Alpha CPU memory model. They are presently implemented for
+x86, x86-64, and PPC systems, and behave as compiler barriers on all
+other CPUs.
+
+In addition to explicit use of the @code{sb-thread:barrier} macro, the
+following functions and macros also serve as @code{:memory} barriers:
+
+@itemize
+@item
+@code{sb-ext:atomic-decf}, @code{sb-ext:atomic-incf}, @code{sb-ext:atomic-push},
+and @code{sb-ext:atomic-pop}.
+@item
+@code{sb-ext:compare-and-swap}.
+@item
+@code{sb-thread:grab-mutex}, @code{sb-thread:release-mutex},
+@code{sb-thread:with-mutex} and @code{sb-thread:with-recursive-lock}.
+@item
+@code{sb-thread:signal-semaphore}, @code{sb-thread:try-semaphore} and
+@code{sb-thread:wait-on-semaphore}.
+@item
+@code{sb-thread:condition-wait}, @code{sb-thread:condition-notify} and
+@code{sb-thread:condition-broadcast}.
+@end itemize
+
+@include macro-sb-thread-barrier.texinfo
+
@node Sessions/Debugging
@comment node-name, next, previous, up
@section Sessions/Debugging
A thread which wishes to create a new session can use
@code{sb-thread:with-new-session} to remove itself from the current
session (which it shares with its parent and siblings) and create a
-fresh one.
+fresh one.
# See also @code{sb-thread:make-listener-thread}.
Within a single session, threads arbitrate between themselves for the
input stream is managed by calls to @code{sb-thread:get-foreground}
(which may block) and @code{sb-thread:release-foreground}.
-@code{sb-ext:quit} terminates all threads in the current session, but
-leaves other sessions running.
-
-@node Implementation (Linux x86)
+@node Foreign threads
+@comment node-name, next, previous, up
+@section Foreign threads
+
+Direct calls to @code{pthread_create} (instead of @code{MAKE-THREAD})
+create threads that SBCL is not aware of, these are called foreign
+threads. Currently, it is not possible to run Lisp code in such
+threads. This means that the Lisp side signal handlers cannot work.
+The best solution is to start foreign threads with signals blocked,
+but since third party libraries may create threads, it is not always
+feasible to do so. As a workaround, upon receiving a signal in a
+foreign thread, SBCL changes the thread's sigmask to block all signals
+that it wants to handle and resends the signal to the current process
+which should land in a thread that does not block it, that is, a Lisp
+thread.
+
+The resignalling trick cannot work for synchronously triggered signals
+(SIGSEGV and co), take care not to trigger any. Resignalling for
+synchronously triggered signals in foreign threads is subject to
+@code{--lose-on-corruption}, see @ref{Runtime Options}.
+
+@node Implementation (Linux x86/x86-64)
@comment node-name, next, previous, up
@section Implementation (Linux x86/x86-64)