9. Threads, Mutexes and Condition Variables
The thread system provides the following data types:
-
Thread (a virtual processor which shares object space with all other threads)
-
Mutex (a mutual exclusion device, also known as a lock and binary semaphore)
-
Condition variable (a set of blocked threads)
The STklos thread system is conform to SRFI-18 (Multithreading support), and implement all the SRFI mechanisms. See this SRFI documentation for a more complete description
9.1. Threads
STklos procedure
Returns a new thread. This thread is not automatically made runnable
(the procedure thread-start!
must be used for this). A thread has the
following fields: name, specific, end-result, end-exception, and a list
of locked/owned mutexes it owns. The thread’s execution consists of a call
to thunk with the "initial continuation". This continuation causes the
(then) current thread to store the result in its end-result field, abandon
all mutexes it owns, and finally terminate. The dynamic-wind
stack of the initial continuation is empty. The optional name is an
arbitrary Scheme object which identifies the thread (useful for debugging);
it defaults to an unspecified value. The specific field is set to an
unspecified value. The thread inherits the dynamic environment from the
current thread. Moreover, in this dynamic environment the exception handler
is bound to the "initial exception handler" which is a unary procedure
which causes the (then) current thread to store in its end-exception
field an "uncaught exception" object whose "reason" is the argument
of the handler, abandon all mutexes it owns, and finally terminate.
The optional parameter stack-size permits to specify
the size (in words) reserved for the thread. This option does not exist
in SRFI-18.
|
STklos procedure
Returns the current thread.
(eq? (current-thread) (current-thread)) => #t
STklos procedure
Makes thread
runnable. The thread
must be a new thread.
Thread-start!
returns the thread.
(let ((t (thread-start! (make-thread
(lambda () (write 'a))))))
(write 'b)
(thread-join! t)) => unspecified
after writing ab or ba
STklos procedure
The current thread exits the running state as if its quantum had
expired. Thread-yield!
returns an unspecified value.
STklos procedure
Causes an abnormal termination of the thread
. If the thread
is not
already terminated, all mutexes owned by the thread
become
unlocked/abandoned and a "terminated thread exception" object is stored
in the thread’s end-exception field. If thread
is the current thread,
thread-terminate!
does not return. Otherwise, thread-terminate!
returns an unspecified value; the termination of the thread will occur
before thread-terminate!
returns.
|
STklos procedure
The current thread waits until the timeout
is reached. This blocks the
thread only if timeout represents a point in the future. It is an error
for timeout to be #f
. Thread-sleep!
returns an unspecified value.
STklos procedure
The current thread waits until the thread
terminates (normally or not)
or until the timeout is reached if timeout
is supplied.
If the timeout is reached, thread-join!
returns timeout-val
if it is
supplied, otherwise a "join timeout exception" is raised.
If the thread
terminated normally, the content of the end-result
field is returned, otherwise the content of the end-exception field
is raised.
(let ((t (thread-start! (make-thread (lambda ()
(expt 2 100))))))
(thread-sleep! 1)
(thread-join! t)) => 1267650600228229401496703205376
STklos procedure
Returns #t
if obj
is a thread, otherwise returns #f
.
(thread? (current-thread)) => #t
(thread? 'foo) => #f
STklos procedure
Returns the name of the thread
.
(thread-name (make-thread (lambda () #f) 'foo)) => foo
STklos procedure
Returns the allocated stack size for thread
.
(thread-stack-size (make-thread (lambda () #f) 'foo 2000)) => 2000
Note that this procedure is not present in SRFI-18.
STklos procedure
Returns the content of the `thread’s specific field.
STklos procedure
Stores obj
into the thread’s specific field. `Thread-specific-set!
returns an unspecified value.
(thread-specific-set! (current-thread) "hello")
=> unspecified
(thread-specific (current-thread))
=> "hello"
9.2. Mutexes
STklos procedure
Returns a new mutex in the unlocked/not-abandoned state. The optional name
is an arbitrary Scheme object which identifies the mutex
(useful for debugging); it defaults to an unspecified value.
The mutex’s specific field is set to an unspecified value.
STklos procedure
Returns #t
if obj is a mutex, otherwise returns #f
.
STklos procedure
Returns the name of the mutex
.
(mutex-name (make-mutex 'foo)) => foo
STklos procedure
Returns the content of the `mutex’s specific field.
STklos procedure
Stores obj
into the `mutex’s specific field and eturns an unspecified value.
(define m (make-mutex))
(mutex-specific-set! m "hello") => unspecified
(mutex-specific m) => "hello"
(define (mutex-lock-recursively! mutex)
(if (eq? (mutex-state mutex) (current-thread))
(let ((n (mutex-specific mutex)))
(mutex-specific-set! mutex (+ n 1)))
(begin
(mutex-lock! mutex)
(mutex-specific-set! mutex 0))))
(define (mutex-unlock-recursively! mutex)
(let ((n (mutex-specific mutex)))
(if (= n 0)
(mutex-unlock! mutex)
(mutex-specific-set! mutex (- n 1)))))
STklos procedure
Returns information about the state of the mutex
. The possible results
are:
-
a thread T: the mutex is in the locked/owned state and thread T is the owner of the mutex
-
the symbol not-owned: the mutex is in the locked/not-owned state
-
the symbol abandoned: the mutex is in the unlocked/abandoned state
-
the symbol not-abandoned: the mutex is in the unlocked/not-abandoned state
(mutex-state (make-mutex)) => not-abandoned
(define (thread-alive? thread)
(let ((mutex (make-mutex)))
(mutex-lock! mutex #f thread)
(let ((state (mutex-state mutex)))
(mutex-unlock! mutex) ; avoid space leak
(eq? state thread))))
STklos procedure
If the mutex
is currently locked, the current thread waits until the
mutex
is unlocked, or until the timeout is reached if timeout
is supplied.
If the timeout
is reached, mutex-lock!
returns #f
.
Otherwise, the state of the mutex is changed as follows:
-
if thread is
#f
the mutex becomes locked/not-owned, -
otherwise, let T be thread (or the current thread if thread is not supplied),
-
if T is terminated the mutex becomes unlocked/abandoned,
-
otherwise mutex becomes locked/owned with T as the owner.
-
After changing the state of the mutex, an "abandoned mutex exception" is
raised if the mutex was unlocked/abandoned before the state change,
otherwise mutex-lock!
returns #t
.
(define (sleep! timeout)
;; an alternate implementation of thread-sleep!
(let ((m (make-mutex)))
(mutex-lock! m #f #f)
(mutex-lock! m timeout #f)))
STklos procedure
Unlocks the mutex
by making it unlocked/not-abandoned. It is not an error
to unlock an unlocked mutex and a mutex that is owned by any thread.
If condition-variable
is supplied, the current thread is blocked and
added to the condition-variable
before unlocking mutex
; the thread
can unblock at any time but no later than when an appropriate call to
condition-variable-signal!
or condition-variable-broadcast!
is
performed (see below), and no later than the timeout (if timeout is
supplied). If there are threads waiting to lock this mutex, the scheduler
selects a thread, the mutex
becomes locked/owned or locked/not-owned,
and the thread is unblocked. mutex-unlock!
returns #f
when the
timeout
is reached, otherwise it returns #t
.
STklos procedure
Executes thunk
, protected by mutex mtx
. The mutex will
be locked before and released after execution of body
, and
also on entrance or departure of its dynamic context
(lock and unlock are used within dynamic-wind
).
9.3. Condition Variables
STklos procedure
Returns a new empty condition variable. The optional name
is an arbitrary
Scheme object which identifies the condition variable (useful for debugging);
it defaults to an unspecified value. The condition variable’s specific
field is set to an unspecified value.
STklos procedure
Returns #t
if obj
is a condition variable, otherwise returns #f
.
STklos procedure
Returns the name of the condition-variable
.
STklos procedure
Returns the content of the `condition-variable’s specific field.
STklos procedure
Stores obj
into the `condition-variable’s specific field.
STklos procedure
If there are threads blocked on the condition-variable
, the scheduler
selects a thread and unblocks it. Condition-variable-signal!
returns
an unspecified value.
STklos procedure
Unblocks all the threads blocked on the condition-variable
.
Condition-variable-broadcast!
returns an unspecified value.
9.4. Conditions
STklos procedure
Returns #t
if obj
is a join timeout exception object,
otherwise returns #f
.
A join timeout exception is raised when thread-join! is called, the timeout is reached and no timeout-val is supplied.
STklos procedure
Returns #t
if obj
is an abandoned mutex exception object,
otherwise returns #f
.
An abandoned mutex exception is raised when the current thread locks
a mutex that was owned by a thread which terminated ,(see mutex-lock!
).
STklos procedure
Returns #t
if obj
is a terminated thread exception object, otherwise
returns #f
.
A terminated thread exception is raised when thread-join! is
called and the target thread has terminated as a result of a call to
thread-terminate!
.
STklos procedure
Returns #t
if obj
is an uncaught exception object, otherwise
returns #f
.
An uncaught exception is raised when thread-join!
is called and the
target thread has terminated because it raised an exception that called
the initial exception handler of that thread.
STklos procedure
Returns the object which was passed to the initial exception handler
of that thread (exc
must be an uncaught exception object).