| Semaphore & Mutex API Function | Description |
|---|---|
| xSemaphoreCreateBinary() | Creates a dynamically allocated binary semaphore |
| xSemaphoreCreateBinaryStatic() | Creates a binary semaphore using user-provided memory |
| xSemaphoreCreateCounting() | Creates a counting semaphore with an initial and maximum count |
| xSemaphoreCreateCountingStatic() | Creates a counting semaphore using user-provided memory |
| xSemaphoreCreateMutex() | Creates a dynamically allocated mutex with priority inheritance |
| xSemaphoreCreateMutexStatic() | Creates a mutex using user-provided memory |
| xSemaphoreGive() | Releases a semaphore from a task |
| xSemaphoreGiveFromISR() | Releases a semaphore from an interrupt handler |
| xSemaphoreTake() | Waits for and obtains a semaphore from a task |
| xSemaphoreTakeFromISR() | Obtains a semaphore from an interrupt handler without blocking |
| xSemaphoreCreateRecursiveMutex() | Creates a mutex that the owner can lock multiple times |
| xSemaphoreCreateRecursiveMutexStatic() | Creates a static recursive mutex using user-provided memory |
| xSemaphoreTakeRecursive() | Locks a recursive mutex; the owner may lock it multiple times |
| xSemaphoreGiveRecursive() | Unlocks a recursive mutex; call once for each successful take |
(1) The task calls xSemaphoreTake() to acquire the semaphore. Since the semaphore is unavailable, Task is placed into the Blocked state until the semaphore becomes available.

(2) An interrupt occurs, and the interrupt service routine (ISR) calls xSemaphoreGiveFromISR() to give the semaphore. As a result, the semaphore becomes available.

(3) Because the semaphore is now available, Task successfully acquires it using xSemaphoreTake(). The task transitions from the Blocked state to the Running (or Ready, depending on the scheduler) state and begins executing the associated processing.

(4) Since a task function typically runs in an infinite loop, after completing the required processing it calls xSemaphoreTake() again to wait for the semaphore. Because the semaphore became unavailable after Step 3, the task enters the Blocked state once again, just as it did in Step 1. It remains blocked until another interrupt occurs and the interrupt service routine (ISR) calls xSemaphoreGiveFromISR() to give the semaphore.
Creates a binary semaphore using memory dynamically allocated from the FreeRTOS heap. A binary semaphore has only two states: available and unavailable, internally represented by a count of 1 or 0. The semaphore is created in the unavailable/empty state, so xSemaphoreGive() must normally be called before the first successful xSemaphoreTake(). It is commonly used for task-to-task or interrupt-to-task synchronization. The function returns a semaphore handle on success or NULL if memory allocation fails.
SemaphoreHandle_t xSemaphoreCreateBinary(void)
// ---------------------- Example ----------------------
SemaphoreHandle_t xBinarySemaphore;
xBinarySemaphore = xSemaphoreCreateBinary();
xSemaphoreGive(xBinarySemaphore);
xSemaphoreTake(xBinarySemaphore, portMAX_DELAY);
xSemaphoreGive(xBinarySemaphore);Creates a binary semaphore without using the FreeRTOS heap. The application provides a StaticSemaphore_t object that stores the semaphore’s internal control information. This buffer must remain valid for the entire lifetime of the semaphore, so it should normally be global or declared with static. Like the dynamically created version, the semaphore starts empty and must be given before it can be taken. Static creation is useful in safety-critical or memory-constrained systems where dynamic allocation is undesirable.
SemaphoreHandle_t xSemaphoreCreateBinaryStatic(StaticSemaphore_t *pxSemaphoreBuffer)Creates a dynamically allocated counting semaphore. uxMaxCount specifies the largest value the semaphore count can reach, while uxInitialCount specifies its starting value and must not exceed the maximum. Every successful xSemaphoreGive() increases the count, and every successful xSemaphoreTake() decreases it. Counting semaphores are commonly used either to count pending events or to manage a pool of identical resources. The function returns a valid handle on success or NULL if allocation fails.
SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount,
UBaseType_t uxInitialCount)
// ---------------------- Example ----------------------
SemaphoreHandle_t xCountSemaphore;
xCountSemaphore = xSemaphoreCreateCounting(255, 0);Creates a counting semaphore using memory supplied by the application. It behaves like xSemaphoreCreateCounting(), but no FreeRTOS heap allocation is performed. The caller provides a persistent StaticSemaphore_t buffer that stores the semaphore’s control structure. The initial count must be less than or equal to the maximum count. This version is useful when all RTOS objects must have deterministic, statically allocated memory.
SemaphoreHandle_t xSemaphoreCreateCountingStatic(UBaseType_t uxMaxCount,
UBaseType_t uxInitialCount,
StaticSemaphore_t * pxSemaphoreBuffer)Creates a dynamically allocated mutex for protecting a shared resource, such as a UART, SPI peripheral, file system, or shared data structure. Unlike a newly created binary semaphore, a newly created mutex starts in the available state and can immediately be taken. A mutex records which task owns it and provides priority inheritance to reduce priority-inversion problems. The task that successfully takes the mutex must be the task that gives it back. Mutexes must not be used from interrupt service routines.
SemaphoreHandle_t xSemaphoreCreateMutex(void)
// ---------------------- Example ----------------------
SemaphoreHandle_t xMutexSemaphore;
xMutexSemaphore = xSemaphoreCreateMutex();Creates a mutex using a user-provided StaticSemaphore_t buffer instead of dynamically allocating memory. It provides the same ownership tracking, mutual-exclusion behavior, and priority inheritance as xSemaphoreCreateMutex(). The buffer must remain allocated for as long as the mutex exists. The mutex is initially available, so no initial xSemaphoreGive() is required. This function is suitable for applications that prohibit heap allocation after startup.
SemaphoreHandle_t xSemaphoreCreateMutexStatic(StaticSemaphore_t *pxMutexBuffer)Releases a semaphore from task context. For a binary semaphore, it changes the state from unavailable to available. For a counting semaphore, it increases the current count by one, provided the maximum count has not already been reached. For a mutex, it releases ownership so another waiting task can acquire the protected resource. The function returns pdTRUE when successful and pdFALSE when the semaphore is already full or cannot be released. It must not be called from an interrupt; use xSemaphoreGiveFromISR() instead.
BaseType_t xSemaphoreGive(xSemaphore)
// ---------------------- Example ----------------------
xSemaphoreGive(xBinarySemaphore);Releases a binary or counting semaphore from an interrupt service routine. If giving the semaphore unblocks a task whose priority is higher than that of the currently running task, *pxHigherPriorityTaskWoken is set to pdTRUE. The ISR should then request a context switch with the port-specific macro, commonly portYIELD_FROM_ISR(). The variable should normally be initialized to pdFALSE before the call. This function cannot be used with mutexes because mutex ownership and priority inheritance require task context.
BaseType_t xSemaphoreGiveFromISR(SemaphoreHandle_t xSemaphore,
BaseType_t * pxHigherPriorityTaskWoken)
// ---------------------- Example ----------------------
SemaphoreHandle_t xBinarySemaphore;
xBinarySemaphore = xSemaphoreCreateBinary();
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(BinarySemaphore, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);Attempts to obtain a binary semaphore, counting semaphore, or standard mutex from task context. If the object is available, the operation succeeds immediately and its count is decreased. If it is unavailable, the calling task can enter the Blocked state for up to xTicksToWait ticks. A value of 0 performs a nonblocking check, while portMAX_DELAY can be used for an indefinite wait when the relevant FreeRTOS configuration permits it. The function returns pdTRUE when the semaphore is obtained and pdFALSE if the waiting time expires.
BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore,
TickType_t xBlockTime)
// ---------------------- Example ----------------------
xSemaphoreTake(xBinarySemaphore, portMAX_DELAY);Attempts to obtain a binary or counting semaphore from an interrupt service routine. It cannot wait or block, so it succeeds only if the semaphore count is already greater than zero. A successful operation decreases the semaphore count and returns pdTRUE; otherwise, it returns pdFALSE. It must not be used with mutexes or recursive mutexes. In most interrupt-to-task synchronization designs, the ISR gives the semaphore and the task takes it, so this function is used less frequently than xSemaphoreGiveFromISR().
BaseType_t xSemaphoreTakeFromISR(SemaphoreHandle_t xSemaphore,
BaseType_t * pxHigherPriorityTaskWoken) Creates a dynamically allocated recursive mutex. A recursive mutex allows its owning task to take the same mutex multiple times without blocking itself. FreeRTOS maintains an internal recursion count that records how many times the owner has successfully taken it. The task must give the mutex exactly the same number of times before another task can acquire it. Recursive mutexes are useful when a protected function calls another function that needs the same lock. They must be used with xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive(), not the standard take and give functions.
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex(void)Creates a recursive mutex using application-provided static memory. Its behavior is identical to the dynamically created recursive mutex, including ownership tracking, priority inheritance, and recursive nesting count. The supplied StaticSemaphore_t buffer must remain valid throughout the mutex’s lifetime. This function avoids heap allocation while still allowing the same task to lock a resource repeatedly. Recursive mutex support must be enabled in FreeRTOSConfig.h.
SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic(StaticSemaphore_t *pxMutexBuffer)Obtains a mutex created specifically as a recursive mutex. The first successful call assigns ownership to the calling task. Additional calls from the same task succeed immediately and increase the recursive nesting count. Calls from other tasks block for up to xTicksToWait while the mutex remains owned. The function returns pdTRUE when the mutex is obtained and pdFALSE if the waiting time expires. It must not be used with a standard mutex created by xSemaphoreCreateMutex().
#define xSemaphoreTakeRecursive(xMutex, xBlockTime)
xQueueTakeMutexRecursive(xMutex, xBlockTime)Releases one level of ownership of a recursive mutex. Each call decreases the mutex’s recursive nesting count by one. The mutex becomes available to other tasks only when the count reaches zero. Therefore, every successful call to xSemaphoreTakeRecursive() must eventually have a matching call to xSemaphoreGiveRecursive(). Only the task that owns the recursive mutex may give it, and the function must not be called from an ISR.
#define xSemaphoreGiveRecursive(xMutex)
xQueueGiveMutexRecursive(xMutex)Back to top of the page