CMSIS-RTOS  Version 1.03
Real-Time Operating System: API and RTX Reference Implementation.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages

Access shared resources simultaneously from different threads. More...

Macros

#define osFeature_Semaphore   30
 maximum count for osSemaphoreCreate function More...
 
#define osSemaphoreDef(name)   const osSemaphoreDef_t os_semaphore_def_##name = { 0 }
 Define a Semaphore object. More...
 
#define osSemaphore(name)   &os_semaphore_def_##name
 Access a Semaphore definition. More...
 

Functions

osSemaphoreId osSemaphoreCreate (const osSemaphoreDef_t *semaphore_def, int32_t count)
 Create and Initialize a Semaphore object used for managing resources. More...
 
int32_t osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec)
 Wait until a Semaphore token becomes available. More...
 
osStatus osSemaphoreRelease (osSemaphoreId semaphore_id)
 Release a Semaphore token. More...
 
osStatus osSemaphoreDelete (osSemaphoreId semaphore_id)
 Delete a Semaphore that was created by osSemaphoreCreate. More...
 

Description

Semaphores are used to manage and protect access to shared resources. Semaphores are very similar to Mutexes. Whereas a Mutex permits just one thread to access a shared resource at a time, a semaphore can be used to permit a fixed number of threads to access a pool of shared resources. Using semaphores, access to a group of identical peripherals can be managed (for example multiple DMA channels).

Semaphore.png
CMSIS-RTOS Semaphore

A semaphore object should be initialized to the maximum number of available tokens. This number of available resources is specified as parameter of the osSemaphoreCreate function. Each time a semaphore token is obtained with osSemaphoreWait, the semaphore count is decremented. When the semaphore count is 0, no semaphore token can be obtained. The thread that tries to obtain the semaphore token needs to wait until the next token is free. Semaphores are released with osSemaphoreRelease incrementing the semaphore count.

Note
Semaphore tokens can be acquired from threads and released from threads and ISRs.

Working with Semaphores

Follow these steps to create and use a semaphore:

  1. Declare the semaphore container and initialize the semaphore:
    osSemaphoreDef (my_semaphore); // Declare semaphore
    osSemaphoreId (my_semaphore_id); // Semaphore ID
  2. Initialize the semaphore container with a number of tokens within a thread:
    my_semaphore_id = osSemaphoreCreate(osSemaphore(my_semaphore), 4); // Create semaphore with 4 tokens
    Important: semaphore tokens can be created and destroyed as threads run. This means that can initialize a semaphore with zero tokens and then use one thread to add/create tokens to the semaphore while a second thread removes them. In this way you can distinguish between producer and consumer threads.
  3. Acquire a token from the semaphore container:
    osSemaphoreWait(my_semaphore_id, osWaitForever);
  4. When finished using the semaphore resource, send the token back to the semaphore container:
    osSemaphoreRelease(my_semaphore_id);

Semaphore Use Cases

Due to their flexibility, semaphores cover a wide range of synchronizing applications. At the same time, they are perhaps the most challenging RTOS object to understand. The following explains a use case for semaphores, taken from the book The Little Book Of Semaphores by Allen B. Downey which is available for free download.

Non-binary Semaphore (Multiplex)

A multiplex limits the number of threads that can access a critical section of code. For example, this could be a function accessing DMA resources which can only support a limited number of calls.

To allow multiple threads to run the function, initialize a semaphore to the maximum number of threads that can be allowed. The number of tokens in the semaphore represents the number of additional threads that may enter. If this number is zero, then the next thread trying to access the function will have to wait until one of the other threads exits and releases its token. When all threads have exited the token number is back to n. Ths following example shows the code for one of the threads that might access the resource:

osSemaphoreDef(multiplex);
osSemaphoreId (multiplex_id);
void thread_n (void)
{
multiplex_id = osSemaphoreCreate(osSemaphore(multiplex), 3);
while(1)
{
// do something
osSemaphoreRelease(multiplex_id);
}
}

Macro Definition Documentation

#define osFeature_Semaphore   30

A CMSIS-RTOS implementation may support semaphores. The value osFeature_Semaphore indicates the maximum index count for a semaphore.

CMSIS-RTOS RTX Setting: osFeature_Semaphore is 65535

#define osSemaphore (   name)    &os_semaphore_def_##name

Access to semaphore object for the functions osSemaphoreCreate.

Parameters
namename of the semaphore object.
Note
CAN BE CHANGED: The parameter to osSemaphore shall be consistent but the macro body is implementation specific in every CMSIS-RTOS.
#define osSemaphoreDef (   name)    const osSemaphoreDef_t os_semaphore_def_##name = { 0 }

Define a semaphore object that is referenced by osSemaphore.

Parameters
namename of the semaphore object.
Note
CAN BE CHANGED: The parameter to osSemaphoreDef shall be consistent but the macro body is implementation specific in every CMSIS-RTOS.

Function Documentation

osSemaphoreId osSemaphoreCreate ( const osSemaphoreDef_t semaphore_def,
int32_t  count 
)
Parameters
[in]semaphore_defsemaphore definition referenced with osSemaphore.
[in]countnumber of available resources.
Returns
semaphore ID for reference by other functions or NULL in case of error.
Note
MUST REMAIN UNCHANGED: osSemaphoreCreate shall be consistent in every CMSIS-RTOS.

Create and initialize a Semaphore object that is used to manage access to shared resources. The parameter count specifies the number of available resources. The count value 1 creates a binary semaphore.

Note
Cannot be called from Interrupt Service Routines.

Code Example

#include "cmsis_os.h"
osThreadId tid_thread1; // ID for thread 1
osThreadId tid_thread2; // ID for thread 2
osSemaphoreId semaphore; // Semaphore ID
osSemaphoreDef(semaphore); // Semaphore definition
//
// Thread 1 - High Priority - Active every 3ms
//
void thread1 (void const *argument) {
int32_t value;
while (1) {
osDelay(3); // Pass control to other tasks for 3ms
val = osSemaphoreWait (semaphore, 1); // Wait 1ms for the free semaphore
if (val > 0) {
// If there was no time-out the semaphore was acquired
: // OK, the interface is free now, use it.
osSemaphoreRelease (semaphore); // Return a token back to a semaphore
}
}
}
//
// Thread 2 - Normal Priority - looks for a free semaphore and uses
// the resource whenever it is available
//
void thread2 (void const *argument) {
while (1) {
osSemaphoreWait (semaphore, osWaitForever); // Wait indefinitely for a free semaphore
// OK, the interface is free now, use it.
:
osSemaphoreRelease (semaphore); // Return a token back to a semaphore.
}
}
// Thread definitions
osThreadDef(thread1, osPriorityHigh, 1, 0);
osThreadDef(thread2, osPriorityNormal, 1, 0);
void StartApplication (void) {
semaphore = osSemaphoreCreate(osSemaphore(semaphore), 1);
tid_thread1 = osThreadCreate(osThread(thread1), NULL);
tid_thread2 = osThreadCreate(osThread(thread2), NULL);
:
}
osStatus osSemaphoreDelete ( osSemaphoreId  semaphore_id)
Parameters
[in]semaphore_idsemaphore object referenced with osSemaphoreCreate.
Returns
status code that indicates the execution status of the function.
Note
MUST REMAIN UNCHANGED: osSemaphoreDelete shall be consistent in every CMSIS-RTOS.

Delete a Semaphore object. The function releases internal memory obtained for Semaphore handling. After this call the semaphore_id is no longer valid and cannot be used. The Semaphore may be created again using the function osSemaphoreCreate.

Status and Error Codes

  • osOK: the semaphore object has been deleted.
  • osErrorISR: osSemaphoreDelete cannot be called from interrupt service routines.
  • osErrorResource: the semaphore object could not be deleted.
  • osErrorParameter: the parameter semaphore_id is incorrect.
Note
Cannot be called from Interrupt Service Routines.
osStatus osSemaphoreRelease ( osSemaphoreId  semaphore_id)
Parameters
[in]semaphore_idsemaphore object referenced with osSemaphoreCreate.
Returns
status code that indicates the execution status of the function.
Note
MUST REMAIN UNCHANGED: osSemaphoreRelease shall be consistent in every CMSIS-RTOS.

Release a Semaphore token. This increments the count of available semaphore tokens.

Note
Interrupt Service Routines can call this function.

Status and Error Codes

  • osOK: the semaphore has been released.
  • osErrorResource: all tokens have already been released.
  • osErrorParameter: the parameter semaphore_id is incorrect.
int32_t osSemaphoreWait ( osSemaphoreId  semaphore_id,
uint32_t  millisec 
)
Parameters
[in]semaphore_idsemaphore object referenced with osSemaphoreCreate.
[in]millisecTimout Value or 0 in case of no time-out.
Returns
number of available tokens, or -1 in case of incorrect parameters.
Note
MUST REMAIN UNCHANGED: osSemaphoreWait shall be consistent in every CMSIS-RTOS.

Wait until a Semaphore token becomes available. When no Semaphore token is available, the function waits for the time specified with the parameter millisec.

The argument millisec specifies how long the system waits for a Semaphore token to become available. While the system waits the thread that is calling this function is put into the state WAITING. The millisec timeout can have the following values:

  • when millisec is 0, the function returns instantly.
  • when millisec is set to osWaitForever the function will wait for an infinite time until the Semaphore token becomes available.
  • all other values specify a time in millisecond for a timeout.

The return value indicates the number of available tokens (the semaphore count value). If 0 is returned, then no semaphore was available.

Note
Cannot be called from Interrupt Service Routines.