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.