1# Semaphore 2 3## Basic Concepts 4 5Semaphore is a mechanism for implementing communication between tasks. It implements synchronization between tasks or exclusive access to shared resources. 6 7In the data structure of a semaphore, there is usually a counter value indicating the available resources. The counter value can be: 8 9- **0**: The semaphore is unavailable. In this case, tasks waiting for the semaphore may exist. 10- Positive number: The semaphore is available. 11 12The usage of the counter value varies with the function of the semaphore. 13 14- If the semaphore is used as a mutex, the counter value indicates the number of units of the shared resources available and its initial value cannot be **0**. The semaphore must be acquired before the shared resource is used, and released after the resource is used. When all shared resources are used, the semaphore counter is reduced to **0** and the tasks that need to obtain the semaphores will be blocked. This ensures exclusive access to shared resources. In addition, when the number of shared resources is **1**, a binary semaphore \(similar to the mutex mechanism\) is recommended. 15- If the semaphore is used for synchronization, the initial semaphore counter value is **0**. When a task fails to acquire the semaphore, it will be blocked and enters Ready or Running state only when the semaphore is released. In this way, task synchronization is implemented. 16 17## Working Principles 18 19### Semaphore control block 20 21``` 22/** 23 * Data structure of the semaphore control block 24 */ 25typedef struct { 26 UINT16 semStat; /* Semaphore status */ 27 UINT16 semType; /* Semaphore type */ 28 UINT16 semCount; /* Semaphore count */ 29 UINT16 semId; /* Semaphore index */ 30 LOS_DL_LIST semList; /* Insert the task blocked by the semaphore to the DL list.*/ 31} LosSemCB; 32``` 33 34### Working Principles 35 36Initializing semaphores: Request memory for the semaphores configured \(the number of semaphores can be configured in the **LOSCFG\_BASE\_IPC\_SEM\_LIMIT** macro by users\), set all semaphores to the unused state, and add them to the linked list for unused semaphores. 37 38Creating a semaphore: Obtain a semaphore from the linked list for unused semaphores and set its initial value. 39 40Requesting a semaphore: If the counter value is greater than **0**, the system allocates a semaphore, decreases the counter value by 1, and returns a success message. If the counter value is **0**, the task is blocked and waits for other tasks to release a semaphore. The waiting timeout period can be set. When a task is blocked by a semaphore, the task will be added to the end of the semaphore waiting task queue. 41 42Releasing a semaphore: If there is no task waiting for the semaphore released, the counter is incremented by 1. Otherwise, wake up the first task in the semaphore waiting queue. 43 44Deleting a semaphore: Set the semaphore in use to the unused state, and adds it to the linked list for unused semaphores. 45 46A semaphore can also be used to limit the number of tasks that can access the shared resource at the same time. When the number of tasks accessing the resource reaches the limit, other tasks will be blocked until a task releases the semaphore. 47 48**Figure 1** Semaphore working mechanism for mini systems<a name="fig467314634214"></a> 49 50 51## Available APIs 52 53<a name="table1078714915105"></a> 54<table><thead align="left"><tr id="row1280518971010"><th class="cellrowborder" valign="top" width="20.1%" id="mcps1.1.4.1.1"><p id="p1380510912104"><a name="p1380510912104"></a><a name="p1380510912104"></a>Function</p> 55</th> 56<th class="cellrowborder" valign="top" width="20.52%" id="mcps1.1.4.1.2"><p id="p08051291106"><a name="p08051291106"></a><a name="p08051291106"></a>API</p> 57</th> 58<th class="cellrowborder" valign="top" width="59.38%" id="mcps1.1.4.1.3"><p id="p12805149151012"><a name="p12805149151012"></a><a name="p12805149151012"></a>Description</p> 59</th> 60</tr> 61</thead> 62<tbody><tr id="row168052913104"><td class="cellrowborder" rowspan="3" valign="top" width="20.1%" headers="mcps1.1.4.1.1 "><p id="p180618915101"><a name="p180618915101"></a><a name="p180618915101"></a>Creating or deleting a semaphore</p> 63</td> 64<td class="cellrowborder" valign="top" width="20.52%" headers="mcps1.1.4.1.2 "><p id="p198061196105"><a name="p198061196105"></a><a name="p198061196105"></a>LOS_SemCreate</p> 65</td> 66<td class="cellrowborder" valign="top" width="59.38%" headers="mcps1.1.4.1.3 "><p id="p1980609121010"><a name="p1980609121010"></a><a name="p1980609121010"></a>Creates a semaphore and returns the semaphore ID.</p> 67</td> 68</tr> 69<tr id="row4806990105"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p280620917109"><a name="p280620917109"></a><a name="p280620917109"></a>LOS_BinarySemCreate</p> 70</td> 71<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p780614919107"><a name="p780614919107"></a><a name="p780614919107"></a>Creates a binary semaphore. The maximum counter value is <strong id="b19111879045016"><a name="b19111879045016"></a><a name="b19111879045016"></a>1</strong>.</p> 72</td> 73</tr> 74<tr id="row17806159151018"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p38067931012"><a name="p38067931012"></a><a name="p38067931012"></a>LOS_SemDelete</p> 75</td> 76<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p168063941015"><a name="p168063941015"></a><a name="p168063941015"></a>Deletes a semaphore.</p> 77</td> 78</tr> 79<tr id="row188061098102"><td class="cellrowborder" rowspan="2" valign="top" width="20.1%" headers="mcps1.1.4.1.1 "><p id="p5806179161014"><a name="p5806179161014"></a><a name="p5806179161014"></a>Requesting or releasing a semaphore</p> 80</td> 81<td class="cellrowborder" valign="top" width="20.52%" headers="mcps1.1.4.1.2 "><p id="p16806159201015"><a name="p16806159201015"></a><a name="p16806159201015"></a>LOS_SemPend</p> 82</td> 83<td class="cellrowborder" valign="top" width="59.38%" headers="mcps1.1.4.1.3 "><p id="p4806149191011"><a name="p4806149191011"></a><a name="p4806149191011"></a>Requests a specified semaphore and sets the timeout period.</p> 84</td> 85</tr> 86<tr id="row4806199141019"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p280618913105"><a name="p280618913105"></a><a name="p280618913105"></a>LOS_SemPost</p> 87</td> 88<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p178061917109"><a name="p178061917109"></a><a name="p178061917109"></a>Posts (releases) a semaphore.</p> 89</td> 90</tr> 91</tbody> 92</table> 93 94## How to Develop 95 961. Call **LOS\_SemCreate** to create a semaphore. To create a binary semaphore, call **LOS\_BinarySemCreate**. 972. Call **LOS\_SemPend** to request a semaphore. 983. Call **LOS\_SemPost** to release a semaphore. 994. Call **LOS\_SemDelete** to delete a semaphore. 100 101> **NOTE:** 102>As interrupts cannot be blocked, semaphores cannot be requested in block mode for interrupts. 103 104## Development Example 105 106### Example Description 107 108This example implements the following: 109 1101. Create a semaphore in task **ExampleSem** and lock task scheduling. Create two tasks **ExampleSemTask1** and **ExampleSemTask2** \(with higher priority\). Enable the two tasks to request the same semaphore. Unlock task scheduling. Enable task **ExampleSem** to enter sleep mode for 400 ticks. Release the semaphore in task **ExampleSem**. 1112. Enable** ExampleSemTask2** to enter sleep mode for 20 ticks after acquiring the semaphore. \(When **ExampleSemTask2** is delayed, **ExampleSemTask1** is woken up.\) 1123. Enable **ExampleSemTask1** to request the semaphore in scheduled block mode, with a wait timeout period of 10 ticks. \(Because the semaphore is still held by **ExampleSemTask2**, **ExampleSemTask1** is suspended. **ExampleSemTask1** is woken up after 10 ticks.\) Enable **ExampleSemTask1** to request the semaphore in permanent block mode after it is woken up 10 ticks later. \(Because the semaphore is still held by **ExampleSemTask2**, **ExampleSemTask1** is suspended.\) 1134. After 20 ticks, **ExampleSemTask2** is woken up and releases the semaphore. **ExampleSemTask1** acquires the semaphore and is scheduled to run. When **ExampleSemTask1** is complete, it releases the semaphore. 1145. Task **ExampleSem** is woken up after 400 ticks and deletes the semaphore. 115 116### Sample Code 117 118The sample code is as follows: 119 120``` 121#include "los_sem.h" 122#include "securec.h" 123 124/* Task ID*/ 125static UINT32 g_testTaskId01; 126static UINT32 g_testTaskId02; 127 128/* Task priority */ 129#define TASK_PRIO_TEST 5 130 131/* Semaphore structure ID */ 132static UINT32 g_semId; 133 134VOID ExampleSemTask1(VOID) 135{ 136 UINT32 ret; 137 138 printf("ExampleSemTask1 try get sem g_semId, timeout 10 ticks.\n"); 139 140 /* Request the semaphore in scheduled block mode, with a wait timeout period of 10 ticks. */ 141 ret = LOS_SemPend(g_semId, 10); 142 143 /* The semaphore is acquired. */ 144 if (ret == LOS_OK) { 145 LOS_SemPost(g_semId); 146 return; 147 } 148 /* The semaphore is not acquired when the timeout period has expired. */ 149 if (ret == LOS_ERRNO_SEM_TIMEOUT) { 150 printf("ExampleSemTask1 timeout and try get sem g_semId wait forever.\n"); 151 152 /* Request the semaphore in permanent block mode. */ 153 ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER); 154 printf("ExampleSemTask1 wait_forever and get sem g_semId.\n"); 155 if (ret == LOS_OK) { 156 LOS_SemPost(g_semId); 157 return; 158 } 159 } 160} 161 162VOID ExampleSemTask2(VOID) 163{ 164 UINT32 ret; 165 printf("ExampleSemTask2 try get sem g_semId wait forever.\n"); 166 167 /* Request the semaphore in permanent block mode. */ 168 ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER); 169 170 if (ret == LOS_OK) { 171 printf("ExampleSemTask2 get sem g_semId and then delay 20 ticks.\n"); 172 } 173 174 /* Enable the task to enter sleep mode for 20 ticks. */ 175 LOS_TaskDelay(20); 176 177 printf("ExampleSemTask2 post sem g_semId.\n"); 178 /* Release the semaphore. */ 179 LOS_SemPost(g_semId); 180 return; 181} 182 183UINT32 ExampleSem(VOID) 184{ 185 UINT32 ret; 186 TSK_INIT_PARAM_S task1; 187 TSK_INIT_PARAM_S task2; 188 189 /* Create a semaphore. */ 190 LOS_SemCreate(0, &g_semId); 191 192 /* Lock task scheduling. */ 193 LOS_TaskLock(); 194 195 /* Create task 1. */ 196 (VOID)memset_s(&task1, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S)); 197 task1.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask1; 198 task1.pcName = "TestTask1"; 199 task1.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; 200 task1.usTaskPrio = TASK_PRIO_TEST; 201 ret = LOS_TaskCreate(&g_testTaskId01, &task1); 202 if (ret != LOS_OK) { 203 printf("task1 create failed.\n"); 204 return LOS_NOK; 205 } 206 207 /* Create task 2. */ 208 (VOID)memset_s(&task2, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S)); 209 task2.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask2; 210 task2.pcName = "TestTask2"; 211 task2.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; 212 task2.usTaskPrio = (TASK_PRIO_TEST - 1); 213 ret = LOS_TaskCreate(&g_testTaskId02, &task2); 214 if (ret != LOS_OK) { 215 printf("task2 create failed.\n"); 216 return LOS_NOK; 217 } 218 219 /* Unlock task scheduling. */ 220 LOS_TaskUnlock(); 221 222 ret = LOS_SemPost(g_semId); 223 224 /* Enable the task to enter sleep mode for 400 ticks. */ 225 LOS_TaskDelay(400); 226 227 /* Delete the semaphore. */ 228 LOS_SemDelete(g_semId); 229 return LOS_OK; 230} 231``` 232 233### Verification 234 235The development is successful if the return result is as follows: 236 237``` 238ExampleSemTask2 try get sem g_semId wait forever. 239ExampleSemTask2 get sem g_semId and then delay 20 ticks. 240ExampleSemTask1 try get sem g_semId, timeout 10 ticks. 241 242ExampleSemTask1 timeout and try get sem g_semId wait forever. 243ExampleSemTask2 post sem g_semId. 244ExampleSemTask1 wait_forever and get sem g_semId. 245``` 246 247