This chapter will discuss services provided by µC/OS-III to manage shared resources. A shared resource is typically a variable (static or global), a data structure, table (in RAM), or registers in an I/O device.
When protecting a shared resource it is preferred to use mutual exclusion semaphores, as will be described in this chapter. Other methods are also presented.
Tasks can easily share data when all tasks exist in a single address space and can reference global variables, pointers, buffers, linked lists, ring buffers, etc. Although sharing data simplifies the exchange of information between tasks, it is important to ensure that each task has exclusive access to the data to avoid contention and data corruption.
For example, when implementing a module that performs a simple time-of-day algorithm in software, the module obviously keeps track of hours, minutes and seconds. The TimeOfDay()
task may appear as shown in the listing below.
Imagine if this task was preempted by another task, after setting the Minutes to 0, because an interrupt occurred and that the other task was more important than the TimeOfDay()
task. Now imagine what will happen if this higher priority task wants to know the current time from the time-of-day module. Since the Hours were not incremented prior to the interrupt, the higher-priority task will read the time incorrectly and, in this case, it will be incorrect by a whole hour.
The code that updates variables for the TimeOfDay()
task must treat all of the variables indivisibly (or atomically) whenever there is possible preemption. Time-of-day variables are considered shared resources and any code that accesses those variables must have exclusive access through what is called a critical section. µC/OS-III provides services to protect shared resources and enables the easy creation of critical sections.
CPU_INT08U Hours; CPU_INT08U Minutes; CPU_INT08U Seconds; void TimeOfDay (void *p_arg) { OS_ERR err; (void)&p_arg; while (DEF_ON) { OSTimeDlyHMSM(0, 0, 1, 0, OS_OPT_TIME_HMSM_STRICT, &err); /* Examine "err" to make sure the call was successful */ Seconds++; if (Seconds > 59) { Seconds = 0; Minutes++; if (Minutes > 59) { Minutes = 0; Hours++; if (Hours > 23) { Hours = 0; } } } } }
The most common methods of obtaining exclusive access to shared resources and to create critical sections are:
- disabling interrupts
- disabling the scheduler
- using semaphores
- using mutual exclusion semaphores (a.k.a. a mutex)
The mutual exclusion mechanism used depends on how fast the code will access a shared resource, as shown in the table below.