Back in the bad old days, the railroad barons discovered that it was bad for business if their trains ran into one another. Their solution to this problem was to use signals called “semaphores.”
When the first train enters the pictured section of track, the semaphore behind it automatically lowers. When a second train arrives, the engineer notes the lowered semaphore, and he stops his train and waits for the semaphore to rise; When the first train leaves that section of trac, the semaphore rises, and the engineer on the second train knows that it is safe to proceed on. There is no possibility of the second train running into the first one.
The general idea of a semaphore in an RTOS is similar to the idea of railroad semaphore. Trains do two things with seniaphores. First, when train leaves the protected section of track, it raises the semaphore. Second, when a train comes to a semaphore, it waits for the semaphore to rise, if necessary, passes through the (now raised) semaphore, and lowers the semaphore. The typical semaphore in an RTOS works rnuch the same way. RTOS Semaphores Although the word was originally coined for particular concept, the word semaphore is now on of the most slippery in the embedded-systems world. It seems to mean almost as many different things as there are software engineers, or at least as there are RTOSs.
Some RTOSs even have more than one kind of semaphore. Also, no RTOS uses the terms raise and lower; they use get and give, take and release, pend and post, p and v, wait and signal, and any number of other combinations. We will use take (for lower) and release (for raise). We’ll discuss first kind of semaphore most commonly called a binary semaphore, which is the kind most similar to the railroad semaphore; we’ll mention a few variations-below.
A typical RTOS binary semaphore works like this: tasks can call two RTOS functions, TakeSemaphore and ReleaseSemaphore. If one task has called TakeSemaphore to take the semaphore and has not called ReleaseSemaphore to release it, then any other task that calls TakeSemaphore will block until the first task calls ReleaseSemaphore. Only one task can have the semaphore at a time.
All the semaphore functions take a parameter that identifies the semaphore that is being initialized, lowered, or raised. Since most RTOSs allow you to have as many semaphores as you like, each call to the RTOS must identify the semaphore on which to operate. The semaphores are all independent of one another: if one task takes semaphore A, another task can take semaphore B without blocking. Similarly, if one task is waiting for semaphore C, that task will still be blocked even if some other task releases semaphore D.
What’s the advantage of having multiple semophores? Whenever a task takes a semaphore, it is potentially slowing the response of any other task that needs the same semaphore. In a system with only one semaphore, if the lowest-priority task takes the semaphore to change data in a shared array, the highest - priority task might block waiting for that semaphore, even if the highest-priority task wants to modify any other data and couldn’t care less about a data in a shared array. By having one semaphore protect the data in a shared array and different semaphore to protect other shared data, you can build your system so the highest priority task can modify it’s data even if the lowest priority task has taken the semaphore protecting it’s shared data.
Different semaphores can correspond to different shared resources. How does the RTOS know which semaphore protects which data? It doesn’t. If you are using multiple semaphores, it is up to' you to remember which semaphore corresponds to which data. A task that is modifying one share data must take the corresponding semaphore. You must decide what shared data each of your semaphores protects.