uCondition

For Internal Scheduling!

Condition Variables

Used with mutexes, condition variables allow threads to block on a condition (e.g., “buffer is not full” or “buffer is not empty”) and be woken up when the condition changes. This mechanism helps in efficiently managing wait states.

The wait and signal operations on condition variables in a monitor are similar to P and V operations on counting semaphores.

In C++, the type uCondition creates a queue object on which tasks can be blocked and reactivated in FIFO order, and is defined:

A condition variable is owned by the mutex object that performs the first wait on it; subsequently, only the owner can wait and signal that condition variable.

  • member routine empty() returns false if there are tasks blocked on the queue and true otherwise.
  • member routine front() returns an integer value stored with the waiting task at the front of the condition queue.
    • it is an error to examine the front of an empty condition queue.

To join a condition queue

The active task calls member wait of the condition variable, e.g.

empty.wait();

which blocks the active task on condition empty, which causes further implicit scheduling.

  • Task is first unblocked from the acceptor/signalled stack, and then from the entry queue.
  • If no waiting task on either, the next call to any mutex member is implicitly accepted

To reactivate a task from condition variable

A task is reactivated from a condition variable when another (active) task executes a signal. Two forms of signal:

Full.signal();

Removes one task from the specified condition variable and push it onto the acceptor/signalled stack. The signaller continues execution and the signalled task is unblocked when it is next popped off the acceptor/signalled stack.

Full.signalBlock();

Removes one task from the specified condition variable and make it the active task, and push the signaller onto the acceptor/signalled stack, like an accept. The signalled task continues execution and the signaller is unblocked when it is next popped off the acceptor/signalled stack.

Differences between condition variable and semaphores

When a task executes a P operation, it does not necessarily block since the semaphore counter may be greater than zero. In contrast, when a task executes a wait it always blocks. a condition can only be used for synchronization no mutual exclusion

When a task executes a V operation on a semaphore it either unblocks a task waiting on that semaphore or, if there is no task to unblock, increments the semaphore counter. In contrast, if a task executes a signal when there is no task to unblock, there is no effect on the condition variable; hence, signals may be lost so the order of executing wait and signals in a monitor is critical.

Tasks awakened by a V can resume execution without delay. In contrast, because tasks execute with mutual exclusion within a monitor, tasks awakened from a condition variable are restarted only when the monitor is next unlocked.

Semaphores can provide finer grain concurrency than a monitor, but at a high cost in complexity.

Example from w23 final

todo : The taxi question