Comtrol eCos User Manual

Page 73

Advertising
background image

Condition Variables

cyg_mutex_lock(&res_lock);

// lock the mutex

res_pool[res_count] = res;

// free the resource

res_count++;

cyg_cond_signal(&res_wait);

// wake up any waiting allocators

cyg_mutex_unlock(&res_lock);

// unlock the mutex

}

In this version of the code, when

res_allocate

detects that there are no resources it calls

cyg_cond_wait

.

This does two things: it unlocks the mutex, and puts the calling thread to sleep on the condition variable. When

res_free

is eventually called, it puts a resource back into the pool and calls

cyg_cond_signal

to wake up any

thread waiting on the condition variable. When the waiting thread eventually gets to run again, it will re-lock the
mutex before returning from

cyg_cond_wait

.

There are two important things to note about the way in which this code works. The first is that the mutex unlock
and wait in

cyg_cond_wait

are atomic: no other thread can run between the unlock and the wait. If this were not

the case then a call to

res_free

by that thread would release the resource but the call to

cyg_cond_signal

would

be lost, and the first thread would end up waiting when there were resources available.

The second feature is that the call to

cyg_cond_wait

is in a

while

loop and not a simple

if

statement. This is

because of the need to re-lock the mutex in

cyg_cond_wait

when the signalled thread reawakens. If there are

other threads already queued to claim the lock then this thread must wait. Depending on the scheduler and the
queue order, many other threads may have entered the critical section before this one gets to run. So the condition
that it was waiting for may have been rendered false. Using a loop around all condition variable wait operations is
the only way to guarantee that the condition being waited for is still true after waiting.

Before a condition variable can be used it must be initialized with a call to

cyg_cond_init

. This requires two

arguments, memory for the data structure and a pointer to an existing mutex. This mutex will not be initialized
by

cyg_cond_init

, instead a separate call to

cyg_mutex_init

is required. If a condition variable is no longer

required and there are no threads waiting on it then

cyg_cond_destroy

can be used.

When a thread needs to wait for a condition to be satisfied it can call

cyg_cond_wait

. The thread must have

already locked the mutex that was specified in the

cyg_cond_init

call. This mutex will be unlocked and the

current thread will be suspended in an atomic operation. When some other thread performs a signal or broadcast
operation the current thread will be woken up and automatically reclaim ownership of the mutex again, allowing it
to examine global state and determine whether or not the condition is now satisfied. The kernel supplies a variant of
this function,

cyg_cond_timed_wait

, which can be used to wait on the condition variable or until some number of

clock ticks have occurred. The mutex will always be reclaimed before

cyg_cond_timed_wait

returns, regardless

of whether it was a result of a signal operation or a timeout.

There is no

cyg_cond_trywait

function because this would not serve any purpose. If a thread has locked the

mutex and determined that the condition is satisfied, it can just release the mutex and return. There is no need to
perform any operation on the condition variable.

When a thread changes shared state that may affect some other thread blocked on a condition variable, it should
call either

cyg_cond_signal

or

cyg_cond_broadcast

. These calls do not require ownership of the mutex, but

usually the mutex will have been claimed before updating the shared state. A signal operation only wakes up the
first thread that is waiting on the condition variable, while a broadcast wakes up all the threads. If there are no
threads waiting on the condition variable at the time, then the signal or broadcast will have no effect: past signals
are not counted up or remembered in any way. Typically a signal should be used when all threads will check the

73

Advertising