STklos Reference Manual

9. Threads, Mutexes and Condition Variables

Contents
| *Top*
1 | Introduction
2 | Expressions
3 | Program structure
4 | Standard Procedures
5 | Regular Expressions
6 | Pattern Matching
7 | Exceptions and Conditions
8 | STklos Object System

9

Threads, Mutexes and Condition Variables

9.1 | Threads
9.2 | Mutexes
9.3 | Condition Variables
9.4 | Conditions

10 | Customizations
11 | The ScmPkg Package System
12 | Foreign Function Interface
13 | Using the SLIB package
14 | SRFIs
15 | Index
| Bibliography

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

`(make-thread thunk)` | STklos procedure

`(make-thread thunk name)`
`(make-thread thunk name stack-size)`
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.
Note: The optional parameter `stack-size` permits to specify the size (in words) reserved for the thread. This option does not exist in SRFI-18.

`(current-thread)` | STklos procedure

Returns the current thread.

>     (eq? (current-thread) (current-thread))  ⇒  #t

`(thread-start! thread)` | 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

`(thread-yield!)` | STklos procedure

The current thread exits the running state as if its quantum had expired. `Thread-yield!` returns an unspecified value.

`(thread-terminate! thread)` | 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.
Note: This operation must be used carefully because it terminates a thread abruptly and it is impossible for that thread to perform any kind of cleanup. This may be a problem if the thread is in the middle of a critical section where some structure has been put in an inconsistent state. However, another thread attempting to enter this critical section will raise an "abandoned mutex exception" because the mutex is unlocked/abandoned.
On Android, `thread-terminate!` can be used only to terminate the current thread. Trying to kill another thread produces an error.

`(thread-sleep! timeout)` | 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.

`(thread-join! thread)` | STklos procedure

`(thread-join! thread timeout)`
`(thread-join! thread timeout timeout-val)`
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

`(thread? obj)` | STklos procedure

Returns `#t` if `obj` is a thread, otherwise returns `#f`.

>     (thread? (current-thread))  ⇒ #t
>     (thread? 'foo)              ⇒ #f

`(thread-name thread)` | STklos procedure

Returns the name of the `thread`.

>     (thread-name (make-thread (lambda () #f) 'foo))  ⇒  foo

`(thread-stack-size thread)` | STklos procedure

Returns the allocated stack size for `thread`. Note that this procedure is not present in SRFI-18.

`(thread-specific thread)` | STklos procedure

Returns the content of the `thread`'s specific field.

`(thread-specific-set! thread)` | 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

`(make-mutex)` | STklos procedure

`(make-mutex name)`
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.

`(mutex? obj)` | STklos procedure

Returns `#t` if obj is a mutex, otherwise returns `#f`.

`(mutex-name mutex)` | STklos procedure

Returns the name of the `mutex`.

>     (mutex-name (make-mutex 'foo))  ⇒  foo

`(mutex-specific mutex)` | STklos procedure

Returns the content of the `mutex`'s specific field.

`(mutex-specific! mutex obj)` | 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)))))

`(mutex-state mutex)` | STklos procedure

Returns information about the state of the `mutex`. The possible results are:

- thread T: the mutex is in the locked/owned state and thread T is the owner of the mutex
- symbol not-owned: the mutex is in the locked/not-owned state
- symbol abandoned: the mutex is in the unlocked/abandoned state
- 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))))

`(mutex-lock! mutex)` | STklos procedure

`(mutex-lock! mutex timeout)`
`(mutex-lock! mutex timeout thread)`
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)))

`(mutex-unlock! mutex)` | STklos procedure

`(mutex-unlock! mutex condition-variable)`
`(mutex-unlock! mutex condition-variable timeout)`
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`.

### 9.3 Condition Variables

`(make-conditon-variable)` | STklos procedure

`(make-conditon-variable name)`
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.

`(conditon-variable? obj)` | STklos procedure

Returns `#t` if `obj` is a condition variable, otherwise returns `#f`.

`(conditon-variable-name conditon-variable)` | STklos procedure

eturns the name of the `condition-variable`.

`(conditon-variable-specific conditon-variable)` | STklos procedure

Returns the content of the `condition-variable`'s specific field.

`(conditon-variable-specific-set! conditon-variable obj)` | STklos procedure

Stores `obj` into the `condition-variable`'s specific field.

`(condition-variable-signal! condition-variable)` | 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.

`(condition-variable-broadcast! condition-variable)` | STklos procedure

Unblocks all the threads blocked on the `condition-variable`. `Condition-variable-broadcast!` returns an unspecified value.

### 9.4 Conditions

`(join-timeout-exception? obj)` | 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.

`(abandoned-mutex-exception? obj)` | 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!`).

`(terminated-thread-exception? obj)` | 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!`.

`(uncaught-exception? obj)` | 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.

`(uncaught-exception-reason exc)` | STklos procedure

Returns the object which was passed to the initial exception handler of that thread (exc must be an "uncaught exception" object).

This Html page has been produced by Skribe.
Last update Wed Nov 24 17:57:14 2021