In this series, we are currently examining the different objects that exist within ThreadX to help developers synchronize events, tasks and move data around their applications. In this post, we are going to examine the most commonly used RTOS object, the semaphore.
A semaphore can play many roles in a real-time embedded application. First and most preferred, is that semaphores are used to notify the application that an event has occurred in the system. For example, a developer using the external interrupt framework using a semaphore to notify the application that an interrupt event has occurred. Second, a semaphore can be used to synchronize thread execution. If a developer has a thread that should always run after another thread, a semaphore can be used to make sure that the threads execute in the correct order. Finally, a semaphore can be used to provide mutual exclusion to a shared resource. An example would be accessing a memory location that is accessed by two or more threads.
Semaphores come in two different flavors, counting and binary semaphores. There really isn’t any difference in the way that the two types are declared in an application but it is often useful to make a distinction between the two. First, a binary semaphore can at most contain a single token; hence, it is binary because the semaphore value is either a 0 or a 1. Binary semaphores are used in an application to provide mutual exclusion when developers decide that they don’t want to use a mutex (which will be discussed in the next post). Counting semaphores are not limited to having only a single token but can have any number deemed necessary by the developer.
A good example for how to create and use semaphores is the Audio Player example project. If a developer opens the projects Synergy Configurator and navigates to the threads tab, they will find an Audio_Thread in the Threads list that they can select. This thread has a g_sf_audio_playback_semaphore that is used to notify the application that an audio event has occurred.
Creating the semaphore is simple. A developer only had to select the green add button in the Audio Thread Objects box and select the semaphore option. Once a semaphore has been created, a developer can select the semaphore and navigate to the Synergy properties window to create the initial settings. The semaphore options can be seen below:
Developers have the ability to set the semaphore name and then the initial token count. In many applications, the token count is initialized to zero since a semaphore is used to signal that an event has occurred. In some cases, a semaphore may be used to show how many resources are available in an application and threads will consume (get) the semaphore when the resource is in use and then return it (put) when the thread is done. Developers who use this pattern would set the initial count for how many resources are available at the application initialization.
The nice part about the Synergy Platform is that developers don’t really need to care about the code that initializes the semaphore. Pressing the Generate Project Content button generates the code necessary to create the semaphore in the application. For developers who are really interested in how this looks, the generated code can be found below:
There are several API’s that a developer can use to interact with the semaphore object. These are detailed in the ThreadX user manual which can be downloaded from the Synergy Gallery. The primary API’s that we will discuss are the following:
UINT tx_semaphore_put(TX_SEMAPHORE *semaphore_ptr)
UINT tx_semaphore_get(TX_SEMAPHORE *semaphore_ptr, ULONG wait_option)
The tx_semaphore_put call will increment the token count by one. The tx_semaphore_get call will attempt to get a token if it is available. If the token count is zero, there is an option to set how long the call will wait for the semaphore to become available before moving on in the code execution. Developers can block forever on a semaphore by using TX_WAIT_FOREVER or not block at all by using TX_NO_WAIT. It is highly recommended that you peruse the ThreadX user manual and examine the additional API’s that can be used with a semaphore.
As was mentioned earlier, semaphores are great for notifying an application that an event has occurred. In the Audio Playback example, the audio framework callback function puts a semaphore to notify the application that data is available as shown below:
The code above will increment the g_sf_audio_playback_semaphore count. The application thread can then have the code shown below that monitors for when the callback event occurs which then executes code associated with the event.
That covers the fundamentals that most engineers will need in order to start using semaphores in their applications. In the next few posts, we will look at mutexes and discuss not just how to use a mutex but also how they differ from a binary semaphore. Until next time,
Live long and profit!
Hot Tip of the Week
Check out the Renesas Synergy Knowledge Base for some previews of the new Synergy Module Guide application notes. These application notes explain the key elements of each module (HAL, Framework or Express Logic) so you can easily select the right module for your application, understand the various APIs available, learn how to configure the module to define the desired functionality, and learn how to use the module from the associated application project. These are preview versions, so please try them out and let us know what you think!
Here are the first available previews: