1# Semaphore<a name="EN-US_TOPIC_0000001078912740"></a> 2 3- [Basic Concepts](#section1577111168131) 4- [Working Principles](#section118423019134) 5- [Development Guidelines](#section01419503131) 6 - [Available APIs](#section1232345431312) 7 - [How to Develop](#section154261711141419) 8 - [Development Example](#section658135571417) 9 - [Example Description](#section125244411653) 10 - [Sample Code](#section1742105514512) 11 - [Verification](#section11297301617) 12 13 14## Basic Concepts<a name="section1577111168131"></a> 15 16Semaphore is a mechanism for implementing inter-task communication. It implements synchronization between tasks or exclusive access to shared resources. 17 18In the data structure of a semaphore, there is a value indicating the number of shared resources available. The value can be: 19 20- **0**: The semaphore is unavailable. Tasks waiting for the semaphore may exist. 21- Positive number: The semaphore is available. 22 23The semaphore for synchronization is different from the semaphore for mutex: 24 25- Semaphore used for exclusive access: The initial semaphore counter value is not 0, indicating the number of shared resources available. The semaphore counter value must be acquired before a 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. 26- Semaphore used for synchronization: The initial semaphore counter value is 0. Task 1 cannot acquire the semaphore and is blocked. Task 1 enters Ready or Running state only when the semaphore is released by task 2. In this way, task synchronization is implemented. 27 28## Working Principles<a name="section118423019134"></a> 29 30Semaphore control block 31 32``` 33/** 34 * Data structure of the semaphore control block 35 */ 36typedef struct { 37 UINT16 semStat; /* Semaphore status */ 38 UINT16 semType; /* Semaphore type*/ 39 UINT16 semCount; /* Semaphore count*/ 40 UINT16 semId; /* Semaphore index*/ 41 LOS_DL_LIST semList; /* Mount the task blocked by the semaphore.*/ 42} LosSemCB; 43``` 44 45Working Principles 46 47Semaphore allows only a specified number of tasks to access a shared resource at a time. When the number of tasks accessing the resource reaches the limit, other tasks will be blocked until the semaphore is released. 48 49- Semaphore initialization 50 51 The system allocates memory for the semaphores configured \(you can configure the number of semaphores using the **LOSCFG\_BASE\_IPC\_SEM\_LIMIT** macro\), initializes all semaphores to be unused semaphores, and adds them to a linked list for the system to use. 52 53- Semaphore creation 54 55 The system obtains a semaphore from the linked list of unused semaphores and assigns an initial value to the semaphore. 56 57- Semaphore request 58 59 If the counter value is greater than 0, the system allocates a semaphore, decreases the value by 1, and returns a success message. Otherwise, the system blocks the task and adds the task to the end of a task queue waiting for semaphores. The wait timeout period can be set. 60 61- Semaphore release 62 63 When a semaphore is released, if there is no task waiting for it, the counter is increased by 1. Otherwise, the first task in the wait queue is woken up. 64 65- Semaphore deletion 66 67 The system sets a semaphore in use to unused state and inserts it to the linked list of unused semaphores. 68 69 70The following figure illustrates the semaphore working mechanism. 71 72**Figure 1** Semaphore working mechanism<a name="fig467314634214"></a> 73 74 75## Development Guidelines<a name="section01419503131"></a> 76 77### Available APIs<a name="section1232345431312"></a> 78 79**Table 1** Semaphore module APIs 80 81<a name="table1415203765610"></a> 82<table><thead align="left"><tr id="row134151837125611"><th class="cellrowborder" valign="top" width="12.85128512851285%" id="mcps1.2.4.1.1"><p id="p16415637105612"><a name="p16415637105612"></a><a name="p16415637105612"></a>Category</p> 83</th> 84<th class="cellrowborder" valign="top" width="29.8029802980298%" id="mcps1.2.4.1.2"><p id="p11415163718562"><a name="p11415163718562"></a><a name="p11415163718562"></a>API</p> 85</th> 86<th class="cellrowborder" valign="top" width="57.34573457345735%" id="mcps1.2.4.1.3"><p id="p1641533755612"><a name="p1641533755612"></a><a name="p1641533755612"></a>Description</p> 87</th> 88</tr> 89</thead> 90<tbody><tr id="row0415737175610"><td class="cellrowborder" rowspan="3" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p8866127195914"><a name="p8866127195914"></a><a name="p8866127195914"></a>Creating or deleting a semaphore</p> 91</td> 92<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p58621910185914"><a name="p58621910185914"></a><a name="p58621910185914"></a>LOS_SemCreate</p> 93</td> 94<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p48623102592"><a name="p48623102592"></a><a name="p48623102592"></a>Creates a semaphore and returns the semaphore ID.</p> 95</td> 96</tr> 97<tr id="row1213865218584"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p20862510115911"><a name="p20862510115911"></a><a name="p20862510115911"></a>LOS_BinarySemCreate</p> 98</td> 99<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1886211011599"><a name="p1886211011599"></a><a name="p1886211011599"></a>Creates a binary semaphore. The maximum counter value is <strong id="b4125169919"><a name="b4125169919"></a><a name="b4125169919"></a>1</strong>.</p> 100</td> 101</tr> 102<tr id="row3231257145813"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p38621410205919"><a name="p38621410205919"></a><a name="p38621410205919"></a>LOS_SemDelete</p> 103</td> 104<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p586261085913"><a name="p586261085913"></a><a name="p586261085913"></a>Deletes a semaphore.</p> 105</td> 106</tr> 107<tr id="row73651459105815"><td class="cellrowborder" rowspan="2" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p16927183515593"><a name="p16927183515593"></a><a name="p16927183515593"></a>Requesting or releasing a semaphore</p> 108</td> 109<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p955271555916"><a name="p955271555916"></a><a name="p955271555916"></a>LOS_SemPend</p> 110</td> 111<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p555221518598"><a name="p555221518598"></a><a name="p555221518598"></a>Requests a specified semaphore and sets the timeout period.</p> 112</td> 113</tr> 114<tr id="row178321454145812"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p17552101519596"><a name="p17552101519596"></a><a name="p17552101519596"></a>LOS_SemPost</p> 115</td> 116<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1555261595915"><a name="p1555261595915"></a><a name="p1555261595915"></a>Posts (releases) a semaphore.</p> 117</td> 118</tr> 119</tbody> 120</table> 121 122### How to Develop<a name="section154261711141419"></a> 123 1241. Call **LOS\_SemCreate** to create a semaphore. To create a binary semaphore, call **LOS\_BinarySemCreate**. 1252. Call **LOS\_SemPend** to request a semaphore. 1263. Call **LOS\_SemPost** to release a semaphore. 1274. Call **LOS\_SemDelete** to delete a semaphore. 128 129> **NOTE:** 130>As interrupts cannot be blocked, semaphores cannot be requested in block mode for interrupts. 131 132### Development Example<a name="section658135571417"></a> 133 134### Example Description<a name="section125244411653"></a> 135 136This example implements the following: 137 1381. 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**. 1392. Enable** ExampleSemTask2** to enter sleep mode for 20 ticks after acquiring the semaphore. \(When **ExampleSemTask2** is delayed, **ExampleSemTask1** is woken up.\) 1403. 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.\) 1414. 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. 1425. Task **ExampleSem** is woken up after 400 ticks and deletes the semaphore. 143 144### Sample Code<a name="section1742105514512"></a> 145 146The sample code is as follows: 147 148``` 149#include "los_sem.h" 150#include "securec.h" 151 152/* Task ID*/ 153static UINT32 g_testTaskId01; 154static UINT32 g_testTaskId02; 155 156/* Task priority */ 157#define TASK_PRIO_TEST 5 158 159/* Semaphore structure ID*/ 160static UINT32 g_semId; 161 162VOID ExampleSemTask1(VOID) 163{ 164 UINT32 ret; 165 166 printf("ExampleSemTask1 try get sem g_semId, timeout 10 ticks.\n"); 167 168 /* Request the semaphore in scheduled block mode, with a wait timeout period of 10 ticks.*/ 169 ret = LOS_SemPend(g_semId, 10); 170 171 /* The semaphore is acquired.*/ 172 if (ret == LOS_OK) { 173 LOS_SemPost(g_semId); 174 return; 175 } 176 /* The semaphore is not acquired when the timeout period has expired.*/ 177 if (ret == LOS_ERRNO_SEM_TIMEOUT) { 178 printf("ExampleSemTask1 timeout and try get sem g_semId wait forever.\n"); 179 180 /* Request the semaphore in permanent block mode.*/ 181 ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER); 182 printf("ExampleSemTask1 wait_forever and get sem g_semId.\n"); 183 if (ret == LOS_OK) { 184 LOS_SemPost(g_semId); 185 return; 186 } 187 } 188} 189 190VOID ExampleSemTask2(VOID) 191{ 192 UINT32 ret; 193 printf("ExampleSemTask2 try get sem g_semId wait forever.\n"); 194 195 /* Request the semaphore in permanent block mode.*/ 196 ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER); 197 198 if (ret == LOS_OK) { 199 printf("ExampleSemTask2 get sem g_semId and then delay 20 ticks.\n"); 200 } 201 202 /* Enable the task to enter sleep mode for 20 ticks.*/ 203 LOS_TaskDelay(20); 204 205 printf("ExampleSemTask2 post sem g_semId.\n"); 206 /* Release the semaphore.*/ 207 LOS_SemPost(g_semId); 208 return; 209} 210 211UINT32 ExampleSem(VOID) 212{ 213 UINT32 ret; 214 TSK_INIT_PARAM_S task1; 215 TSK_INIT_PARAM_S task2; 216 217 /* Create a semaphore.*/ 218 LOS_SemCreate(0, &g_semId); 219 220 /* Lock task scheduling.*/ 221 LOS_TaskLock(); 222 223 /* Create task 1.*/ 224 (VOID)memset_s(&task1, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S)); 225 task1.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask1; 226 task1.pcName = "TestTask1"; 227 task1.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; 228 task1.usTaskPrio = TASK_PRIO_TEST; 229 ret = LOS_TaskCreate(&g_testTaskId01, &task1); 230 if (ret != LOS_OK) { 231 printf("task1 create failed .\n"); 232 return LOS_NOK; 233 } 234 235 /* Create task 2.*/ 236 (VOID)memset_s(&task2, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S)); 237 task2.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask2; 238 task2.pcName = "TestTask2"; 239 task2.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; 240 task2.usTaskPrio = (TASK_PRIO_TEST - 1); 241 ret = LOS_TaskCreate(&g_testTaskId02, &task2); 242 if (ret != LOS_OK) { 243 printf("task2 create failed.\n"); 244 return LOS_NOK; 245 } 246 247 /* Unlock task scheduling.*/ 248 LOS_TaskUnlock(); 249 250 ret = LOS_SemPost(g_semId); 251 252 /* Enable the task to enter sleep mode for 400 ticks.*/ 253 LOS_TaskDelay(400); 254 255 /* Delete the semaphore. */ 256 LOS_SemDelete(g_semId); 257 return LOS_OK; 258} 259``` 260 261### Verification<a name="section11297301617"></a> 262 263The development is successful if the return result is as follows: 264 265``` 266ExampleSemTask2 try get sem g_semId wait forever. 267ExampleSemTask2 get sem g_semId and then delay 20 ticks. 268ExampleSemTask1 try get sem g_semId, timeout 10 ticks. 269ExampleSemTask1 timeout and try get sem g_semId wait forever. 270ExampleSemTask2 post sem g_semId. 271ExampleSemTask1 wait_forever and get sem g_semId. 272``` 273 274