Miking offers a set of externals for shared-memory parallelism using atomic operations and threads running on multiple cores.
The parallel programming primitives consist of atomic references and functions for creating and synchronizing threads. In addition to the examples below, more documentation can be found in the standard library at stdlib/multicore.
Atomic references are similar to ordinary references, except that operations performed on them are atomic, which means that no other execution thread can interfere with the result. In other words, they are safe to use in multi-threaded execution. Atomic references are provided in multicore/atomic.mc.
atomicMake creates a new atomic reference and gives it an initial value. The
value of the atomic reference can be read by
let a = atomicMake 0 in
utest atomicGet a with 0 in
atomicCAS a oldVal newVal performs an atomic compare-and-set, that is, it only
updates the value of
newVal if the current value is identical to
oldVal, and then returns a Boolean representing if the update was successful
utest atomicCAS a 0 1 with true in
utest atomicCAS a 42 3 with false in
utest atomicGet a with 1 in
The compare-and-set operation is currently supported for integer atomic references only.
To unconditionally set the value of an atomic reference, we can use
atomicExchange, which also returns the old value of the reference:
utest atomicExchange a 2 with 1 in
Finally, for integer references, we can use
atomicFetchAndAdd to increase or
decrease the value of the reference. The function returns the old value of the
utest atomicFetchAndAdd a 1 with 2 in
-- Current value is now 3
utest atomicFetchAndAdd a (subi 0 45) with 3 in
-- Current value is now -42
Functions for handling threads are provided in multicore/threads.mc. The following example program spawns 10 threads that compete for printing their IDs:
let place = atomicMake 1 in
let threads = create 10 (lam. threadSpawn (lam.
[int2string (atomicFetchAndAdd place 1)
, ": thread ID "
, int2string (threadSelf ())
map threadJoin threads
threadSpawn takes a function of type
() -> a as argument
threadSelf returns the ID of the current thread. Note that
threadJoin must be called once for each call to
output of the above program might be:
1: thread ID 1
2: thread ID 2
3: thread ID 129
4: thread ID 130
5: thread ID 3
6: thread ID 257
7: thread ID 258
8: thread ID 131
9: thread ID 385
10: thread ID 386
However, the values and order of the thread IDs might be different over different runs.
Externals for probability distributions are defined in
stdlib/ext/dist-ext.mc. To use these, you must install the
opam install owl)