![]() If a low priority task owns a resource that a higher priority also needs to access, the RTOS changes the priority of the lower priority task to match the priority of the higher priority task so that the owner of the mutex can complete its access to the resource as soon as possible and, free the resource. This is done through an API provide by the RTOS. As with the semaphore, a mutex needs to be initialized before you can attempt to acquire/release it. Mutexes)Ī mutex is a special type of binary semaphore and is used to eliminate unbounded priority inversions. You can find a detailed description of priority inversions in my ♜/OS-III books and specifically, chapter 13 (i.e., section 13.3.5). Generally speaking, it’s preferable to NOT use semaphores because they are subject to unbounded priority inversions! Instead, you should use mutexes. Whenever you need access to the resource, you’d call the RTOS API to acquire the semaphore (i.e., get a key) and when done, call the RTOS API to release the semaphore.You’d initialize the binary semaphore to 1 and the counting semaphore to N (the number of identical resources you can share). You need to decide whether you need a binary or counting semaphore.If no buffer was available, the calling task would be suspended until a buffer was freed by one of the tasks that owns one of the buffers (assuming the waiting task has the highest priority). If one is available (the semaphore value was > 0) then your buffer allocator would give the caller a buffer. Each time you’d need a buffer from the buffer pool, you would call the RTOS API to acquire a key. An example of where you’d use a counting semaphore is in the management of a buffer pool of identical buffers. ![]() The counting semaphore has a value of 0 when all keys have been allocated to tasks, and > 0 when keys are available. ![]() In the time-of-day clock implementation, you would use a binary semaphore since you would only need a single clock in your application time-zones can easily be handled with offsets from the time-of-day clock.Ī counting semaphore contains multiple keys because there are multiple identical resources available. In this case, the semaphore value is either 0 indicating that the key is in use by another task or 1, the key is available. There are two types of semaphores: binary and counting.Ī binary semaphore contains a single key. Your application can declare any number of semaphores, each one protecting different resources. A semaphore needs to be initialized before it can be used. As you might expect, you are not actually getting a physical key, you get a virtual one. This key needs to be released once the task is done accessing the shared resource. Without getting into too many details, a semaphore is a key that a task needs to acquire before proceeding to access a resource (as we’ve seen in Listing 2). Listing 2, Simple Time-of-Day Clock with resource sharing protection. Release Semaphore (or mutex) // API depends on your RTOS Listing 1, Simple Time-of-Day Clock without resource sharing protection.Īcquire Semaphore (or mutex) // API depends on your RTOS The exact API to use depends on the RTOS you are using. In an RTOS based system, the task would need to wrap the shared resources using a semaphore or a mutex as shown in Listing 2. I’ll get into which one to use and when, shortly. RTOSs provide such services (i.e., APIs) through semaphores and mutual exclusion semaphores (a.k.a. Time-of-day variables are considered shared resources and any code that accesses those variables must have exclusive access to all the variables. The code that updates variables for the TimeOfDayTask() task must treat all of the variables indivisibly (or atomically) whenever there is possible preemption. Since the Hours variable was not incremented prior to the interrupt, the higher-priority task would read the time incorrectly and, in this case, it would be incorrect by a whole hour. ![]() Now imagine what would happen if this higher priority task wanted to know (i.e., read) the current time. Imagine if this task was preempted (triggered by an interrupt) by another task just after setting the Minutes to 0 and, the other task was more important than the TimeOfDayTask(). In fact, you can find such a module in Chapter 6 of my Embedded Systems Building Blocks book. The task only keeps track of hours, minutes and seconds but could easily be expanded to support day, day-of-month, month, year, and leap year. I’ll use as an example a task that performs a simple time-of-day clock implemented in software. 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. 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.
0 Comments
Leave a Reply. |