3.83. kink/thread/MUTEX¶
Provides non-reentrant mutex locks.
3.83.1. type mutex¶
A mutex is a non-reentrant mutual exclusion lock. A mutex can also be used as a conditional variable on itself.
For a mutex, at the most one thread can hold the mutex.
If a thread is holding the mutex, the thread cannot acquire the mutex again. Namely, it is not reentrant.
Example: a simple semaphore:
:MUTEX.require_from('kink/thread/')
:new_semaphore <- {(:Capa)
:V = new_val('Count' 0)
:Mut = MUTEX.new
new_val(
'acquire' {
Mut.with_lock{
Mut.wait_until{ V.Count < Capa }
V:Count <- V.Count + 1
}
}
'release' {
Mut.with_lock{
V:Count <- V.Count - 1
Mut.notify_all
}
}
)
}
§§ Design note: Why non-reentrant?
A mutex is designed to be non-reentrant, because a non-reentrant mutex:
• Can detect imbalanced lock-unlock correspondence earlier, and
• Makes a programmer more careful about a critical section boundary
Mutex.lock¶
Mutex.lock acquires the Mutex.
Precondition:
• The current thread must NOT hold the mutex
If the Mutex is held by another thread, the current thread blocks until it is available.
Mutex.unlock¶
Mutex.unlock releases the mutex.
Precondition:
• The current thread must hold the Mutex
Mutex.with_lock($thunk)¶
Mutex.with_lock calls $thunk holding the Mutex. This is a convenient wrapper method for .lock and .unlock.
Precondition:
• The current thread must NOT hold the lock
Mutex.with_lock acquires the Mutex before invoking $thunk, and releases the Mutex after $thunk returns a val, raising an exception, or escaping (see kink/CONTROL.escape).
Mutex.wait(...[Timeout_seconds = plus infinity])¶
`wait` blocks the thread until waken up.
Preconditions:
• The current thread must hold `Mutex`
• If `Timeout_seconds` is specified, it must be a non-negative num
Calling .wait method releases `Mutex` until it gets waken up. When the thread gets waken up, the thread acquires `Mutex` again.
The thread gets waken when:
• Another thread calls .notify_all method for `Mutex`,
• `Timeout_seconds` passes, or
• “Spurious wakeup” happens; namely without any trigger within your program
Because of existence of “spurious wakeup,” you should always test the status which is waited for.
See POSIX specification for “spurious wakeup.”
http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html
Mutex.wait_until($ok_thunk?)¶
Mutex.wait_until blocks the thread until waken up, and $ok_thunk? returns true.
This is a convenient wrapper method for .wait.
Precondition:
• The current thread must hold a lease of the lock.
Note that $ok_thunk? is called in the current thread while holding the Mutex.
Mutex.notify_all¶
Mutex.notify_all makes all the threads which is waiting for the Mutex via .wait method waken up when the Mutex is available.
Precondition:
• The current thread must hold a lease of the lock.
3.83.2. MUTEX.is?(Val)¶
MUTEX.is? returns whether the Val is a mutex.
3.83.3. MUTEX.new¶
MUTEX.new makes a new mutex.