What you'll learn:
- Issues with proprietary RTOS APIs.
- How does the POSIX pthread API stack up against proprietary APIs?
- Thread creation in POSIX.
A quick internet search shows a seemingly endless number of real-time operating systems (RTOSes), most based on proprietary application programming interfaces (APIs). That’s certainly true for the more popular embedded RTOSes, e.g., FreeRTOS, ThreadX, and Zephyr. Some of these proprietary RTOS APIs provide adequate functionality.
However, each proprietary API impedes embedded development by requiring extensive developer training, constricting cross-platform code sharing, and effectively locking the application to the proprietary RTOS.
Developer training is time-consuming and expensive. In addition, proprietary API usage errors resulting in product defects are all too common. For device makers with MPU- (Linux) and MCU- (RTOS) based designs, sharing code between platforms is difficult, if not impossible.
Finally, since the application is locked into the RTOS, it’s at the mercy of what processor and development tools are supported by that particular RTOS. Not having the ability to freely migrate your application to another hardware platform or development tool might be the most significant impediment of all.
But instead of focusing on the negative aspects of proprietary RTOS APIs, it’s more productive to focus on solutions. Interestingly, the answer has been around since 1995. This is when the POSIX Threads standard (commonly called pthreads) was introduced (IEEE 1003.1c-a995). Not only is this an international standard, it’s also the multithreading API in every embedded Linux distribution. Hence, POSIX pthreads is already the most popular API standard in the embedded industry.
Is the POSIX pthread API as functionally capable as proprietary RTOS APIs? Here’s a brief overview of the POSIX pthread API alongside the most popular proprietary RTOS APIs.
Creating Threads in POSIX
Creating threads (also called tasks) is the most fundamental RTOS primitive. The POSIX pthread create API is ideally suited for embedded applications. Having only four arguments, it’s much simpler than other popular RTOS APIs. The POSIX pthread API offers an optional attribute specification if additional configuration is required. Here are the thread creation APIs for POSIX pthreads, ThreadX, FreeRTOS, and Zephyr:
IEEE POSIX pthread standard
Proprietary RTOS APIs
ThreadX:
FreeRTOS:
Zephyr:
Using Mutual Exclusion with POSIX
Mutual exclusion is required in embedded systems to coordinate access to shared resources. The mutual-exclusion primitives in POSIX are similar to the APIs in other RTOS. One difference in POSIX is that additional APIs offer timeouts for waiting on a mutex. Most proprietary RTOS APIs have an additional parameter that determines the timeout. Here are the typically used mutual-exclusion APIs for POSIX pthreads, ThreadX, FreeRTOS, and Zephyr:
IEEE POSIX prthread API for creating a mutex
POSIX:
Proprietary RTOS API for creating a mutex
ThreadX:
FreeRTOS:
Zephyr:
IEEE POSIX pthread API for locking a mutex
Proprietary RTOS API for locking a mutex
ThreadX:
FreeRTOS:
Zephyr:
IEEE POSIX pthread API for unlocking a mutex
Proprietary RTOS API for unlocking a mutex
ThreadX:
FreeRTOS:
Zephyr:
Multiple Thread Synchronization Using POSIX
Synchronizing the execution of multiple threads is an important RTOS primitive. A classic example is the producer-consumer paradigm, whereby one thread processes information produced by another thread or interrupt handler.
Counting semaphores is often utilized in a producer-consumer fashion. The thread responsible for processing the information waits for a semaphore. When the information is ready, the producer sends the semaphore.
POSIX semaphore APIs are similar to proprietary RTOS semaphore APIs. One difference is that POSIX has additional APIs when a timeout is required to wait for a semaphore. Most proprietary RTOS APIs have an additional parameter that determines the timeout. Here are the commonly used semaphore APIs for POSIX, ThreadX, FreeRTOS, and Zephyr:
IEEE POSIX API to create a semaphore
Proprietary RTOS APIs to create a semaphore
ThreadX:
FreeRTOS:
Zephyr:
IEEE POSIX API to obtain a semaphore
Proprietary RTOS APIs to obtain a semaphore
ThreadX:
FreeRTOS:
Zephyr:
IEEE POSIX API to post a semaphore
Proprietary RTOS API to post a semaphore
ThreadX:
FreeRTOS:
Zephyr:
Thread Communication in POSIX
Communicating information between multiple threads for processing is another important RTOS primitive. The thread responsible for processing the information can wait for a message from a queue. When the message is available, the waiting thread is given the message for processing and is resumed.
POSIX message-passing APIs are similar to proprietary RTOS APIs. There are differences, though. POSIX supports variable-sized messages and message priority. POSIX also has additional APIs when suspension timeouts are required. Most proprietary RTOS APIs have an additional parameter that determines the message waiting timeout. Here are the commonly used message queue APIs for POSIX, ThreadX, FreeRTOS, and Zephyr:
IEEE POSIX Message Queue Create API
Proprietary RTOS Message Queue Create APIs
ThreadX:
FreeRTOS:
Zephyr:
IEEE POSIX Message Send API
Proprietary RTOS Message Send API
ThreadX:
FreeRTOS:
Zephyr:
IEEE POSIX Message Receive API
Proprietary RTOS Message Receive APIs
ThreadX:
FreeRTOS:
Zephyr:
POSIX pthread API vs. Proprietary RTOS APIs
It's clear that the POSIX pthread API is similar and just as capable as proprietary RTOS APIs for the most common multithreading primitives associated with thread management, mutual exclusion, synchronization, and message passing. The POSIX API is actually more straightforward in some cases—like creating a thread. Any missing functionality in POSIX can be augmented with API extensions.
Since most developers have some experience with POSIX pthreads, training and usage errors are significantly reduced or even eliminated. Sharing code with embedded Linux and/or moving to another RTOS that supports POSIX pthreads is easy. RTOS migration to the industry-standard IEEE POSIX pthread API promises to reduce time-to-market and enhance code reuse—welcome advances in our embedded industry.