1# Semaphore 2 3 4## Basic Concepts 5 6Semaphore is a mechanism for implementing communication between tasks. It implements synchronization between tasks or exclusive access to shared resources. 7 8In the data structure of a semaphore, there is usually a counter value indicating the available resources. The counter value can be: 9 10- **0**: The semaphore is unavailable. In this case, tasks waiting for the semaphore may exist. 11 12- Positive number: The semaphore is available. 13 14Semaphores can be used to solve a problem of mutual exclusion or process synchronization. The usage of the counter value varies with the function of the semaphore. 15 16- If the semaphore is used to solve a problem of mutual exclusion, 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. 17 18- If the semaphore is used to solve a problem of process 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 or an interrupt. In this way, task synchronization is implemented. 19 20 21## Working Principles 22 23 24### Semaphore Control Block 25 26 27``` 28/** 29 * Data structure of the semaphore control block 30 */ 31typedef struct { 32 UINT16 semStat; /* Semaphore status */ 33 UINT16 semType; /* Semaphore type */ 34 UINT16 semCount; /* Semaphore count */ 35 UINT16 semId; /* Semaphore index */ 36 LOS_DL_LIST semList; /* Insert the task blocked by the semaphore to the DL list. */ 37} LosSemCB; 38``` 39 40 41### Working Principles 42 43Initializing semaphores: Request memory for the semaphores configured (the number of semaphores can be configured in the **LOSCFG_BASE_IPC_SEM_LIMIT** macro), set all semaphores to the unused state, and add them to the linked list for unused semaphores. 44 45Creating a semaphore: Obtain a semaphore from the linked list for unused semaphores and set its initial value. 46 47Semaphore request: 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. 48 49When 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. 50 51Semaphore deletion: The system sets a semaphore in use to the unused state and inserts it to the linked list of unused semaphores. 52 53A semaphore places a limit on the number of tasks accessing the shared resource concurrently. When the number of tasks accessing the shared resource reaches the maximum, other tasks that attempt to obtain the resource are blocked until a semaphore is released. 54 55**Figure 1** Semaphore working mechanism for the mini system 56![](figures/semaphore-working-mechanism-for-mini-systems.png "semaphore-working-mechanism-for-mini-systems") 57 58 59## Available APIs 60 61| Category| Description| 62| -------- | -------- | 63| Creating or deleting a semaphore| **LOS_SemCreate**: creates a semaphore and returns the semaphore ID.<br>**LOS_BinarySemCreate**: creates a binary semaphore. The maximum count value is **1**.<br>**LOS_SemDelete**: deletes a semaphore.| 64| Requesting or releasing a semaphore| **LOS_SemPend**: requests a semaphore and sets the timeout period.<br>**LOS_SemPost**: releases a semaphore.| 65 66 67## How to Develop 68 691. Call **LOS_SemCreate** to create a semaphore. To create a binary semaphore, call **LOS_BinarySemCreate**. 70 712. Call **LOS_SemPend** to request a semaphore. 72 733. Call **LOS_SemPost** to release a semaphore. 74 754. Call **LOS_SemDelete** to delete a semaphore. 76 77 78> **NOTE**<br> 79> As interrupts cannot be blocked, semaphores cannot be requested in block mode for interrupts. 80 81 82## Development Example 83 84 85### Example Description 86 87This example implements the following: 88 891. Create a semaphore for the **ExampleSem** task, and lock task scheduling. Create two tasks **ExampleSemTask1** and **ExampleSemTask2**. The priority of **ExampleSemTask2** is higher than that of **ExampleSemTask1**. **ExampleSemTask1** and **ExampleSemTask2** apply for the same semaphore. Make **ExampleSemTask2** sleep for 20 ticks after acquiring the semaphore. Make **ExampleSemTask1** to apply for the semaphore with a timeout period of 10 ticks. If **ExampleSemTask1** still fails to acquire the semaphore after 10 ticks, **ExampleSemTask1** will wait until a semaphore is acquired. Unlock task scheduling. **ExampleSemTask1** and **ExampleSemTask2** are blocked and attempt to acquire a semaphore. The **ExampleSem** task releases the semaphore. 90 912. **ExampleSemTask2** (which has the higher priority) acquires the semaphore and starts to sleep for 20 ticks. In this case, **ExampleSemTask1** is woken up. 92 933. **ExampleSemTask1** requests a semaphore with a timeout period of 10 ticks. During this period, the semaphore is still held by **ExampleSemTask2**, therefore, **ExampleSemTask1** is suspended. After 10 ticks, **ExampleSemTask1** is woken up and waits permanently to acquire a semaphore. **ExampleSemTask1** is suspended. 94 954. 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. 96 975. After 400 ticks, **ExampleSem** is woken up and deletes the semaphore. 98 99 100### Sample Code 101 102The sample code is as follows: 103 104The sample code is compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. Call **ExampleSem** in **TestTaskEntry**. 105 106 107``` 108#include "los_sem.h" 109 110/* Semaphore structure ID */ 111static UINT32 g_semId; 112 113VOID ExampleSemTask1(VOID) 114{ 115 UINT32 ret; 116 117 printf("ExampleSemTask1 try get sem g_semId, timeout 10 ticks.\n"); 118 /* Request the semaphore in scheduled block mode, with a wait timeout period of 10 ticks. */ 119 ret = LOS_SemPend(g_semId, 10); 120 /* The semaphore is acquired. */ 121 if (ret == LOS_OK) { 122 LOS_SemPost(g_semId); 123 return; 124 } 125 126 /* The semaphore is not acquired when the timeout period has expired. */ 127 if (ret == LOS_ERRNO_SEM_TIMEOUT) { 128 printf("ExampleSemTask1 timeout and try get sem g_semId wait forever.\n"); 129 /* Request the semaphore in permanent block mode. */ 130 ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER); 131 printf("ExampleSemTask1 wait_forever and get sem g_semId.\n"); 132 if (ret == LOS_OK) { 133 LOS_SemPost(g_semId); 134 return; 135 } 136 } 137} 138 139VOID ExampleSemTask2(VOID) 140{ 141 UINT32 ret; 142 printf("ExampleSemTask2 try get sem g_semId wait forever.\n"); 143 144 /* Request the semaphore in permanent block mode. */ 145 ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER); 146 if (ret == LOS_OK) { 147 printf("ExampleSemTask2 get sem g_semId and then delay 20 ticks.\n"); 148 } 149 150 /* Enable the task to enter sleep mode for 20 ticks. */ 151 LOS_TaskDelay(20); 152 printf("ExampleSemTask2 post sem g_semId.\n"); 153 154 /* Release the semaphore. */ 155 LOS_SemPost(g_semId); 156 return; 157} 158 159UINT32 ExampleSem(VOID) 160{ 161 UINT32 ret; 162 TSK_INIT_PARAM_S task1 = { 0 }; 163 TSK_INIT_PARAM_S task2 = { 0 }; 164 UINT32 taskId1; 165 UINT32 taskId2; 166 167 /* Create a semaphore. */ 168 LOS_SemCreate(0, &g_semId); 169 170 /* Lock task scheduling. */ 171 LOS_TaskLock(); 172 173 /* Create task 1. */ 174 task1.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask1; 175 task1.pcName = "TestTask1"; 176 task1.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; 177 task1.usTaskPrio = 5; 178 ret = LOS_TaskCreate(&taskId1, &task1); 179 if (ret != LOS_OK) { 180 printf("task1 create failed.\n"); 181 return LOS_NOK; 182 } 183 184 /* Create task 2. */ 185 task2.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask2; 186 task2.pcName = "TestTask2"; 187 task2.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; 188 task2.usTaskPrio = 4; 189 ret = LOS_TaskCreate(&taskId2, &task2); 190 if (ret != LOS_OK) { 191 printf("task2 create failed.\n"); 192 return LOS_NOK; 193 } 194 195 /* Unlock task scheduling. */ 196 LOS_TaskUnlock(); 197 198 ret = LOS_SemPost(g_semId); 199 200 /* Enable the task to enter sleep mode for 400 ticks. */ 201 LOS_TaskDelay(400); 202 203 /* Delete the semaphore. */ 204 LOS_SemDelete(g_semId); 205 return LOS_OK; 206} 207``` 208 209 210### Verification 211 212The development is successful if the return result is as follows: 213 214 215 216``` 217ExampleSemTask2 try get sem g_semId wait forever. 218ExampleSemTask1 try get sem g_semId, timeout 10 ticks. 219ExampleSemTask2 get sem g_semId and then delay 20 ticks. 220ExampleSemTask1 timeout and try get sem g_semId wait forever. 221ExampleSemTask2 post sem g_semId. 222ExampleSemTask1 wait_forever and get sem g_semId. 223``` 224