* Semaphores are a fundamental threading construct -- export them.
Clean up the interface slightly: not (SETF SEMAPHORE-COUNT), note
that being a subclass of STRUCTURE-OBJECT is not guaranteed, etc.
locking at the correct granularity. In the current implementation it is
still safe to have multiple readers access the same table, but it's not
guaranteed that this property will be maintained in future releases.
+ * enhancement: SB-THREAD package now exports a semaphore interface.
* enhancement: CONS can now stack-allocate on x86 and
x86-64. (Earlier LIST and LIST* supported stack-allocation, but
CONS did not.)
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.
threading on Darwin (Mac OS X) and FreeBSD on the x86 is experimental.
@menu
-* Threading basics::
-* Special Variables::
-* Mutex Support::
-* Waitqueue/condition variables::
-* Sessions/Debugging::
-* Implementation (Linux x86)::
+* Threading basics::
+* Special Variables::
+* Mutex Support::
+* Semaphores::
+* Waitqueue/condition variables::
+* Sessions/Debugging::
+* Implementation (Linux x86)::
@end menu
@node Threading basics
@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
+
+escribed here should be considered
+experimental, subject to API changes without notice.
+
+@include struct-sb-thread-semaphore.texinfo
+@include fun-sb-thread-make-semaphore.texinfo
+@include fun-sb-thread-semaphore-count.texinfo
+@include fun-sb-thread-semaphore-name.texinfo
+@include fun-sb-thread-signal-semaphore.texinfo
+@include fun-sb-thread-wait-on-semaphore.texinfo
+
@node Waitqueue/condition variables
@comment node-name, next, previous, up
@section Waitqueue/condition variables
There are three components:
@itemize
-@item
+@item
the condition itself (not represented in code)
-@item
+@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
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
"WAITQUEUE" "MAKE-WAITQUEUE" "WAITQUEUE-NAME"
"CONDITION-WAIT" "CONDITION-NOTIFY" "CONDITION-BROADCAST"
"MAKE-LISTENER-THREAD"
- "RELEASE-FOREGROUND" "WITH-NEW-SESSION"))
+ "RELEASE-FOREGROUND"
+ "WITH-NEW-SESSION"
+ ;; Semaphores
+ "MAKE-SEMAPHORE"
+ "SEMAPHORE"
+ "SEMAPHORE-NAME"
+ "SEMAPHORE-COUNT"
+ "SIGNAL-SEMAPHORE"
+ "WAIT-ON-SEMAPHORE"))
#s(sb-cold:package-data
:name "SB!LOOP"
;;;; semaphores
-(defstruct (semaphore (:constructor %make-semaphore))
+(defstruct (semaphore (:constructor %make-semaphore (name %count)))
#!+sb-doc
- "Semaphore type."
+ "Semaphore type. The fact that a SEMAPHORE is a STRUCTURE-OBJECT
+should be considered an implementation detail, and may change in the
+future."
(name nil :type (or null simple-string))
- (count 0 :type (integer 0))
+ (%count 0 :type (integer 0))
(mutex (make-mutex))
(queue (make-waitqueue)))
+(setf (fdocumentation 'semaphore-name 'function)
+ "The name of the semaphore INSTANCE. Setfable.")
+
+(declaim (inline semaphore-count))
+(defun semaphore-count (instance)
+ "Returns the current count of the semaphore INSTANCE."
+ (semaphore-%count instance))
+
(defun make-semaphore (&key name (count 0))
#!+sb-doc
- "Create a semaphore with the supplied COUNT."
- (%make-semaphore :name name :count count))
+ "Create a semaphore with the supplied COUNT and NAME."
+ (%make-semaphore name count))
-(setf (fdocumentation 'semaphore-name 'function)
- "The name of the semaphore. Setfable.")
-
-(defun wait-on-semaphore (sem)
+(defun wait-on-semaphore (semaphore)
#!+sb-doc
- "Decrement the count of SEM if the count would not be negative. Else
-block until the semaphore can be decremented."
+ "Decrement the count of SEMAPHORE if the count would not be
+negative. Else blocks until the semaphore can be decremented."
;; a more direct implementation based directly on futexes should be
;; possible
- (with-mutex ((semaphore-mutex sem))
- (loop until (> (semaphore-count sem) 0)
- do (condition-wait (semaphore-queue sem) (semaphore-mutex sem))
- finally (decf (semaphore-count sem)))))
+ (with-mutex ((semaphore-mutex semaphore))
+ (loop until (> (semaphore-%count semaphore) 0)
+ do (condition-wait (semaphore-queue semaphore) (semaphore-mutex semaphore))
+ finally (decf (semaphore-%count semaphore)))))
-(defun signal-semaphore (sem &optional (n 1))
+(defun signal-semaphore (semaphore &optional (n 1))
#!+sb-doc
- "Increment the count of SEM by N. If there are threads waiting on
-this semaphore, then N of them is woken up."
- (declare (type (and fixnum (integer 1)) n))
- (with-mutex ((semaphore-mutex sem))
- (when (= n (incf (semaphore-count sem) n))
- (condition-notify (semaphore-queue sem) n))))
+ "Increment the count of SEMAPHORE by N. If there are threads waiting
+on this semaphore, then N of them is woken up."
+ (declare (type (integer 1) n))
+ (with-mutex ((semaphore-mutex semaphore))
+ (when (= n (incf (semaphore-%count semaphore) n))
+ (condition-notify (semaphore-queue semaphore) n))))
;;;; job control, independent listeners
;;; checkins which aren't released. (And occasionally for internal
;;; versions, especially for internal versions off the main CVS
;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"1.0.10.27"
+"1.0.10.28"