The threads library
The threads library allows concurrent programming in Caml Special Light.
It provides multiple threads of control (also called lightweight
processes) that execute concurrently in the same memory space. Threads
communicate by in-place modification of shared data structures, or by
sending and receiving data on communication channels.
The threads library is implemented by time-sharing on a single
processor. It will not take advantage of multi-processor machines.
Using this library will therefore never make programs run
faster. However, many programs are easier to write when structured as
several communicating processes.
This library cannot be used in native-code programs compiled with
cslopt; it can only be used with bytecode programs
compiled with cslc.
Programs that use the threads library must be linked as follows:
cslc -custom other options threads.cma other files -cclib -lthreads
Interactive use through a toplevel built with cslmktop is
impractical, because the Caml Special Light toplevel itself is not
thread-aware.
Module Thread: user-level lightweight threads
type t
-
The type of thread identifiers.
Thread creation and termination
val new : ('a -> 'b) -> 'a -> t
-
new funct arg creates a new thread of control, in which the
function application funct arg is executed concurrently
with the other threads of the program. The application of new
returns the identifier of the newly created thread.
The new thread terminates when the application funct arg
returns, either normally or by raising an uncaught exception.
In the latter case, the exception is printed on standard error,
but not propagated back to the parent thread. Similarly, the
result of the application funct arg is discarded and not
directly accessible to the parent thread.
val self : unit -> t
-
Return the identifier of the calling thread.
val exit : unit -> unit
-
Terminate prematurely the calling thread.
val kill : t -> unit
-
Terminate prematurely the thread whose identifier is given.
Suspending threads
val delay: float -> unit
-
delay d suspends the execution of the calling thread for
d seconds. The other program threads continue to run during
this time.
val wait_inchan : in_channel -> unit
-
wait_inchan ic suspends the execution of the calling thread
until at least one character is available for reading on the
input channel ic. The other program threads continue to run
during this time. In contrast, calling an input function directly
on ic would block all threads in the program until data is
available on the channel. See the module ThreadIO for
higher-level input functions compatible with threads.
val wait_descr : Unix.file_descr -> unit
-
Similar to wait_inchan, but operates on a file descriptor
from the Unix library instead of an input channel.
val join : t -> unit
-
join th suspends the execution of the calling thread
until the thread th has terminated.
Low-level thread synchronization primitives
-
The following primitives provide the basis for implementing
synchronization functions between threads. Their direct use is
discouraged, as they are very low-level and prone to race conditions
and deadlocks. The modules Mutex, Condition and Event
provide higher-level synchronization primitives.
val critical_section: bool ref
-
Setting this reference to true deactivate thread preemption
(the timer interrupt that transfers control from thread to thread),
causing the current thread to run uninterrupted until
critical_section is reset to false or the current thread
explicitely relinquishes control using sleep, delay,
wait_inchan or wait_descr.
val sleep : unit -> unit
-
Suspend the calling thread until another thread reactivates it
using wakeup. Just before suspending the thread,
critical_section is reset to false. Resetting
critical_section and suspending the calling thread is an
atomic operation.
val wakeup : t -> unit
-
Reactivate the thread whose identifier is given. This thread
is assumed to be suspended on a call to sleep, delay,
wait_inchan or wait_descr. After the call to wakeup,
the suspended thread will resume execution at some future time.
wakeup does nothing if the thread was not suspended.
Module Mutex: locks for mutual exclusion
-
Mutexes (mutual-exclusion locks) are used to implement critical sections
and protect shared mutable data structures against concurrent accesses.
The typical use is (if m is the mutex associated with the data structure
D):
Mutex.lock m;
(* Critical section that operates over D *);
Mutex.unlock m
type t
-
The type of mutexes.
val new: unit -> t
-
Return a new mutex.
val lock: t -> unit
-
Lock the given mutex. Only one thread can have the mutex locked
at any time. A thread that attempts to lock a mutex already locked
by another thread will suspend until the other thread unlocks
the mutex.
val try_lock: t -> bool
-
Same as try_lock, but does not suspend the calling thread if
the mutex is already locked: just return false immediately
in that case. If the mutex is unlocked, lock it and
return true.
val unlock: t -> unit
-
Unlock the given mutex. Other threads suspended trying to lock
the mutex will restart.
Module Condition: condition variables to synchronize between threads
-
Condition variables are used when one thread wants to wait until another
thread has finished doing something: the former thread ``waits'' on the
condition variable, the latter thread ``signals'' the condition when it
is done. Condition variables should always be protected by a mutex.
The typical use is (if D is a shared data structure, m its mutex,
and c is a condition variable):
Mutex.lock m;
while (* some predicate P over D is not satisfied *) do
Condition.wait c m
done;
(* Modify D *)
if (* the predicate P over D is now satified *) then Condition.signal c;
Mutex.unlock m
type t
-
The type of condition variables.
val new: unit -> t
-
Return a new condition variable.
val wait: t -> Mutex.t -> unit
-
wait c m atomically unlocks the mutex m and suspends the
calling process on the condition variable c. The process will
restart after the condition variable c has been signalled.
The mutex m is locked again before wait returns.
val signal: t -> unit
-
signal c restarts one of the processes waiting on the
condition variable c.
val broadcast: t -> unit
-
broadcast c restarts all processes waiting on the
condition variable c.
Module Event: first-class synchronous communication
-
This module implements synchronous interprocess communications over
channels. As in John Reppy's Concurrent ML system, the communication
events are first-class values: they can be built and combined
independently before being offered for communication.
type 'a channel
-
The type of communication channels carrying values of type 'a.
val new_channel: unit -> 'a channel
-
Return a new channel.
type 'a event
-
The type of communication events returning a result of type 'a.
val send: 'a channel -> 'a -> unit event
-
send ch v returns the event consisting in sending the value v
over the channel ch. The result value of this event is ().
val receive: 'a channel -> 'a event
-
receive ch returns the event consisting in receiving a value
from the channel ch. The result value of this event is the
value received.
val choose: 'a event list -> 'a event
-
choose evl returns the event that is the alternative of
all the events in the list evl.
val wrap: 'a event -> ('a -> 'b) -> 'b event
-
wrap ev fn returns the event that performs the same communications
as ev, then applies the post-processing function fn
on the return value.
val guard: (unit -> 'a event) -> 'a event
-
guard fn returns the event that, when synchronized, computes
fn() and behaves as the resulting event. This allows to
compute events with side-effects at the time of the synchronization
operation.
val sync: 'a event -> 'a
-
``Synchronize'' on an event: offer all the communication
possibilities specified in the event to the outside world,
and block until one of the communications succeed. The result
value of that communication is returned.
val select: 'a event list -> 'a
-
``Synchronize'' on an alternative of events.
select evl is shorthand for sync(choose el).
val poll: 'a event -> 'a option
-
Non-blocking version of sync: offer all the communication
possibilities specified in the event to the outside world,
and if one can take place immediately, perform it and return
Some r where r is the result value of that communication.
Otherwise, return None without blocking.