Priority inversion – Comtrol eCos User Manual

Page 66

Advertising
background image

Mutexes

Sections of code like the above which involve manipulating shared data are generally known as critical regions.
Code should claim a lock before entering a critical region and release the lock when leaving. Mutexes provide an
appropriate synchronization primitive for this.

static volatile int counter = 0;

static cyg_mutex_t

lock;

void

process_event(void)

{

...

cyg_mutex_lock(&lock);

counter++;

cyg_mutex_unlock(&lock);

}

A mutex must be initialized before it can be used, by calling

cyg_mutex_init

. This takes a pointer to a

cyg_mutex_t data structure which is typically statically allocated, and may be part of a larger data structure. If a
mutex is no longer required and there are no threads waiting on it then

cyg_mutex_destroy

can be used.

The main functions for using a mutex are

cyg_mutex_lock

and

cyg_mutex_unlock

. In normal operation

cyg_mutex_lock

will return success after claiming the mutex lock, blocking if another thread currently owns the

mutex. However the lock operation may fail if other code calls

cyg_mutex_release

or

cyg_thread_release

,

so if these functions may get used then it is important to check the return value. The current owner of a mutex
should call

cyg_mutex_unlock

when a lock is no longer required. This operation must be performed by the

owner, not by another thread.

cyg_mutex_trylock

is a variant of

cyg_mutex_lock

that will always return immediately, returning success or

failure as appropriate. This function is rarely useful. Typical code locks a mutex just before entering a critical
region, so if the lock cannot be claimed then there may be nothing else for the current thread to do. Use of this
function may also cause a form of priority inversion if the owner owner runs at a lower priority, because the
priority inheritance code will not be triggered. Instead the current thread continues running, preventing the owner
from getting any cpu time, completing the critical region, and releasing the mutex.

cyg_mutex_release

can be used to wake up all threads that are currently blocked inside a call to

cyg_mutex_lock

for a specific mutex. These lock calls will return failure. The current mutex owner is not

affected.

Priority Inversion

The use of mutexes gives rise to a problem known as priority inversion. In a typical scenario this requires three
threads A, B, and C, running at high, medium and low priority respectively. Thread A and thread B are temporarily
blocked waiting for some event, so thread C gets a chance to run, needs to enter a critical region, and locks a mutex.
At this point threads A and B are woken up - the exact order does not matter. Thread A needs to claim the same
mutex but has to wait until C has left the critical region and can release the mutex. Meanwhile thread B works on
something completely different and can continue running without problems. Because thread C is running a lower
priority than B it will not get a chance to run until B blocks for some reason, and hence thread A cannot run either.
The overall effect is that a high-priority thread A cannot proceed because of a lower priority thread B, and priority
inversion has occurred.

66

Advertising