]> begriffs open source - cmsis/blob - CMSIS/DoxyGen/RTOS2/src/cmsis_os2_Sema.txt
RTOS2 Documentation Updates
[cmsis] / CMSIS / DoxyGen / RTOS2 / src / cmsis_os2_Sema.txt
1 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
2 //  ==== Semaphore Management ====
3 /** 
4 \addtogroup CMSIS_RTOS_SemaphoreMgmt Semaphores
5 \ingroup CMSIS_RTOS
6 \brief Access shared resources simultaneously from different threads.
7 \details 
8 Semaphores are used to manage and protect access to shared resources. Semaphores are very similar to
9 \ref CMSIS_RTOS_MutexMgmt "Mutexes". Whereas a Mutex permits just one thread to access a shared resource at a
10 time, a semaphore can be used to permit a fixed number of threads to access a pool of shared resources. Using semaphores,
11 access to a group of identical peripherals can be managed (for example multiple DMA channels).
12
13 \image html "Semaphore.png" "CMSIS-RTOS Semaphore"
14
15 A semaphore object should be initialized to the maximum number of available tokens. This number of available resources is
16 specified as parameter of the \ref osSemaphoreNew function. Each time a semaphore token is obtained with
17 \ref osSemaphoreAcquire, the semaphore count is decremented. When the semaphore count is 0, no semaphore token can be
18 obtained. The thread that tries to obtain the semaphore token needs to wait until the next token is free. Semaphores are
19 released with \ref osSemaphoreRelease incrementing the semaphore count.
20
21 \note Semaphore tokens can be acquired from threads and released from threads and ISRs.
22
23 Working with Semaphores
24 --------------------
25 Follow these steps to create and use a semaphore:
26 -# Declare the semaphore container and initialize the semaphore:
27 \code{.c}
28 osSemaphoreId_t  my_semaphore_id
29 \endcode
30 -# Initialize the semaphore container with a number of tokens within a thread:
31 \code{.c}
32 my_semaphore_id = osSemaphoreNew(4, 0, NULL);  // Create semaphore with 4 tokens
33 \endcode
34 \b Important: semaphore tokens can be created and destroyed as threads run. This means that can initialize a semaphore with
35 zero tokens and then use one thread to add/create tokens to the semaphore while a second thread removes them. In this way you
36 can distinguish between producer and consumer threads.
37 -# Acquire a token from the semaphore container:
38 \code{.c}
39 osSemaphoreAcquire(my_semaphore_id, osWaitForever);
40 \endcode
41 -# When finished using the semaphore resource, send the token back to the semaphore container:
42 \code{.c}
43 osSemaphoreRelease(my_semaphore_id);
44 \endcode
45
46 Semaphore Use Cases
47 -------------------
48 Due to their flexibility, semaphores cover a wide range of synchronizing applications. At the same time, they are perhaps the
49 most challenging RTOS object to understand. The following explains a use case for semaphores, taken from the book
50 <a href="http://www.greenteapress.com/semaphores/" target="_blank">The Little Book Of Semaphores</a> by Allen B. Downey which
51 is available for free download.
52
53 <b>Non-binary Semaphore (Multiplex)</b>
54
55 A multiplex limits the number of threads that can access a critical section of code. For example, this could be a function
56 accessing DMA resources which can only support a limited number of calls.
57
58 To allow multiple threads to run the function, initialize a semaphore to the maximum number of threads that can be allowed.
59 The number of tokens in the semaphore represents the number of additional threads that may enter. If this number is zero,
60 then the next thread trying to access the function will have to wait until one of the other threads exits and releases its
61 token. When all threads have exited the token number is back to n. Ths following example shows the code for one of the
62 threads that might access the resource:
63
64 \code{.c}
65 osSemaphoreId_t multiplex_id;
66  
67 void thread_n (void)
68   {
69     multiplex_id = osSemaphoreNew(3, 0, NULL);
70     while(1)
71       {
72         osSemaphoreAcquire(multiplex_id, osWaitForever);
73         // do something
74         osSemaphoreRelease(multiplex_id);
75       }
76   }
77 \endcode
78
79 @{
80 */
81 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
82 /**
83 \typedef  osSemaphoreId_t
84 \details
85
86 */
87 /**
88 \struct osSemaphoreAttr_t
89 \details
90
91 */
92 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
93 /**
94 \fn osSemaphoreId_t osSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr)
95 \details
96 Create and initialize a Semaphore object that is used to manage access to shared resources. The parameter \em count specifies the number of available resources. 
97 The \em max_count value 1 creates a binary semaphore.
98
99 <b>Code Example</b>
100 \code{.c}
101 #include "cmsis_os2.h"
102    
103 osThreadId_t tid_thread1;                          // ID for thread 1
104 osThreadId_t tid_thread2;                          // ID for thread 2
105   
106 osSemaphoreId_t semaphore;                         // Semaphore ID
107    
108 //
109 //   Thread 1 - High Priority - Active every 3ms
110 //
111 void thread1 (void *argument) {
112   int32_t value;
113
114   while (1) {
115     osDelay(3);                                  // Pass control to other tasks for 3ms
116     val = osSemaphoreAcquire (semaphore, 1);     // Wait 1ms for the free semaphore
117     if (val > 0) {
118                                                  // If there was no time-out the semaphore was acquired
119       :                                          // OK, the interface is free now, use it.
120       osSemaphoreRelease (semaphore);            // Return a token back to a semaphore
121     }
122   }
123 }
124   
125 //
126 //   Thread 2 - Normal Priority - looks for a free semaphore and uses
127 //                                the resource whenever it is available
128 //
129 void thread2 (void *argument) {
130   while (1) {
131     osSemaphoreAcquire (semaphore, osWaitForever);  // Wait indefinitely for a free semaphore
132                                                  // OK, the interface is free now, use it.
133     :
134     osSemaphoreRelease (semaphore);              // Return a token back to a semaphore.
135   }
136 }
137   
138   
139 void StartApplication (void) {
140   semaphore = osSemaphoreNew(osSemaphore(semaphore), 1);
141
142   tid_thread1 = osThreadCreate(thread1, NULL, NULL);
143   tid_thread2 = osThreadCreate(thread2, NULL, NULL);
144   :
145 }
146 \endcode
147
148
149 */
150 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
151 /**
152 \fn osStatus_t osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout)
153 \details
154 Wait until a Semaphore token becomes available and acquires it for the thread if available. 
155 When no Semaphore token is available, the function waits for the time specified with the parameter \em timeout.
156
157 The argument \a timeout specifies how long the system waits for a Semaphore token to become available.
158 While the system waits the thread that is calling this function is put into the state \b BLOCKED.
159 The \a millisec timeout can have the following values:
160  - when \a timeout is 0, the function returns instantly.
161  - when \a timeout is set to \b osWaitForever the function will wait for an infinite time until the Semaphore token becomes available.
162  - all other values specify a time in kernel ticks for a timeout.
163
164 The return value indicates the number of available tokens (the semaphore count value). If 0 is returned, then no semaphore was available.
165
166 */
167 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
168 /**
169 \fn osStatus_t osSemaphoreRelease (osSemaphoreId_t semaphore_id)
170 \details
171 Release a Semaphore token.  This increments the count of available semaphore tokens.
172
173 \ref osStatus_t return values:
174  - \em osOK: the semaphore has been released.
175  - \em osErrorResource: all tokens have already been released.
176  - \em osErrorParameter: the parameter \a semaphore_id is incorrect.
177 */
178 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
179 /**
180 \fn uint32_t osSemaphoreGetCount (osSemaphoreId_t semaphore_id)
181 \details
182 Returns the count of available semaphores of the semaphore object specified by \em semaphore_id.
183
184 */
185 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
186 /**
187 \fn osStatus_t osSemaphoreDelete (osSemaphoreId_t semaphore_id)
188 \details
189 Delete a Semaphore object.  The function releases internal memory obtained for Semaphore handling.  After this call the \a semaphore_id is no longer valid and cannot be
190 used. The Semaphore may be created again using the function \ref osSemaphoreNew.
191
192 \ref osStatus_t return values:
193  - \em osOK: the semaphore object has been deleted.
194  - \em osErrorISR: \ref osSemaphoreDelete cannot be called from interrupt service routines.
195  - \em osErrorResource: the semaphore object could not be deleted.
196  - \em osErrorParameter: the parameter \a semaphore_id is incorrect.
197
198 \note Cannot be called from \ref CMSIS_RTOS_ISR_Calls "Interrupt Service Routines".
199 Calling \ref osSemaphoreDelete from an ISR will return \ref osErrorISR.
200  */
201 /// @}