mutex


mutex(@optional name = void)
      

Return a new mutex in the unlocked/not-abandoned state.

A mutex can be in one of four states: locked (either owned or not owned) and unlocked (either abandoned or not abandoned). An attempt to lock a mutex only succeeds if the mutex is in an unlocked state, otherwise the current task will wait. A mutex in the locked/owned state has an associated owner task, which by convention is the task that is responsible for unlocking the mutex (this case is typical of critical sections implemented as "lock mutex, perform operation, unlock mutex"). A mutex in the locked/not-owned state is not linked to a particular task.

A mutex becomes locked when a task locks it using the mutex_lock function. A mutex becomes unlocked/abandoned when the owner of a locked/owned mutex terminates. A mutex becomes unlocked/not-abandoned when a task unlocks it using the mutex_unlock function.

The mutex primitives do not implement recursive mutex semantics. An attempt to lock a mutex that is locked implies that the current task waits even if the mutex is owned by the current task (this can lead to a deadlock if no other task unlocks the mutex).

Each mutex has a specific field which can be used in an application specific way to associate data with the mutex.

Examples:


// updating shared state without a data race:          
let x = 0
let mx = mutex()

function incx()
{ mutex_lock(mx)
  x = inc(x)
  mutex_unlock(mx) }

!incx()
!incx()
x
// 2

// an abstraction to make sure a mutex is unlocked,
// even if the critical section throws an unhandled error.
// usage: !call_with_mutex(a_function, a_mutex)
function call_with_mutex(fn, m)
{ mutex_lock(m)
  try fn()
  finally mutex_unlock(m) }

// multiple locks/unlocks from the same task:
function mutex_lock_recursively(m)
  if (mutex_state(m) == self())
   mutex_set_data(m, inc(mutex_data(m)))
  else
  { mutex_lock(m)
    mutex_set_data(m, 0) }

function mutex_unlock_recursively(m)
  if (is_zero(mutex_data(m)))
    mutex_unlock(m)
  else mutex_set_data(m, dec(mutex_data(m)))

// usage example:  
!{ mutex_lock_recursively(mx)
   showln(1)
   mutex_lock_recursively(mx)
   showln(2)
   mutex_unlock_recursively(mx)
   showln(1)
   mutex_unlock_recursively(mx)
   showln("bye") }
//> 1
    2
    1
    bye
      

Also see:

monitor
rvar


Core Module Index | Contents