1e41f4b71Sopenharmony_ci# Semaphore 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ci 4e41f4b71Sopenharmony_ci## Basic Concepts 5e41f4b71Sopenharmony_ci 6e41f4b71Sopenharmony_ciSemaphore is a mechanism used to implement synchronization between tasks or exclusive access to shared resources. 7e41f4b71Sopenharmony_ci 8e41f4b71Sopenharmony_ciIn the semaphore data structure, there is a value indicating the number of shared resources available. The value can be: 9e41f4b71Sopenharmony_ci 10e41f4b71Sopenharmony_ci- **0**: The semaphore is unavailable. In this case, tasks waiting for the semaphore may exist. 11e41f4b71Sopenharmony_ci 12e41f4b71Sopenharmony_ci- Positive number: The semaphore is available. 13e41f4b71Sopenharmony_ci 14e41f4b71Sopenharmony_ciThe semaphore used for exclusive access to resources is different from the semaphore used for synchronization: 15e41f4b71Sopenharmony_ci 16e41f4b71Sopenharmony_ci- Semaphore used for exclusive access: The initial semaphore counter value \(non-zero\) indicates the number of shared resources available. A semaphore must be acquired before a shared resource is used, and released when the resource is no longer required. When all shared resources are used, the semaphore counter is reduced to 0 and all tasks requiring the semaphore will be blocked. This ensures exclusive access to shared resources. In addition, if the number of shared resources is 1, a binary semaphore \(similar to the mutex mechanism\) is recommended. 17e41f4b71Sopenharmony_ci 18e41f4b71Sopenharmony_ci- Semaphore used for synchronization: The initial semaphore counter value is **0**. A task without the semaphore will be blocked, and enters the Ready or Running state only when the semaphore is released by another task or an interrupt. 19e41f4b71Sopenharmony_ci 20e41f4b71Sopenharmony_ci 21e41f4b71Sopenharmony_ci## Working Principles 22e41f4b71Sopenharmony_ci 23e41f4b71Sopenharmony_ci**Semaphore Control Block** 24e41f4b71Sopenharmony_ci 25e41f4b71Sopenharmony_ci 26e41f4b71Sopenharmony_ci``` 27e41f4b71Sopenharmony_ci/** 28e41f4b71Sopenharmony_ci * Data structure of the semaphore control block 29e41f4b71Sopenharmony_ci */ 30e41f4b71Sopenharmony_citypedef struct { 31e41f4b71Sopenharmony_ci UINT16 semStat; /* Semaphore status */ 32e41f4b71Sopenharmony_ci UINT16 semType; /* Semaphore type */ 33e41f4b71Sopenharmony_ci UINT16 semCount; /* Semaphore count */ 34e41f4b71Sopenharmony_ci UINT16 semId; /* Semaphore ID */ 35e41f4b71Sopenharmony_ci LOS_DL_LIST semList; /* List of blocked tasks */ 36e41f4b71Sopenharmony_ci} LosSemCB; 37e41f4b71Sopenharmony_ci``` 38e41f4b71Sopenharmony_ci 39e41f4b71Sopenharmony_ci**Working Principles** 40e41f4b71Sopenharmony_ci 41e41f4b71Sopenharmony_ciSemaphore 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. 42e41f4b71Sopenharmony_ci 43e41f4b71Sopenharmony_ci- Semaphore initialization 44e41f4b71Sopenharmony_ci 45e41f4b71Sopenharmony_ci Allocate memory for the semaphores (the number of semaphores is specified by the **LOSCFG_BASE_IPC_SEM_LIMIT** macro), set all semaphores to the unused state, and add them to a linked list. 46e41f4b71Sopenharmony_ci 47e41f4b71Sopenharmony_ci- Semaphore creation 48e41f4b71Sopenharmony_ci 49e41f4b71Sopenharmony_ci Obtain a semaphore from the linked list of unused semaphores and assign an initial value to the semaphore. 50e41f4b71Sopenharmony_ci 51e41f4b71Sopenharmony_ci- Semaphore request 52e41f4b71Sopenharmony_ci 53e41f4b71Sopenharmony_ci If the counter value is greater than 0 when a semaphore is requsted, the counter is decreased by 1 and a success message is returned. Otherwise, the task is blocked and added to the end of a task queue waiting for semaphores. The wait timeout period can be set. 54e41f4b71Sopenharmony_ci 55e41f4b71Sopenharmony_ci- Semaphore release 56e41f4b71Sopenharmony_ci 57e41f4b71Sopenharmony_ci If no task is waiting for the semaphore, the counter is incremented by 1. Otherwise, wake up the first task in the wait queue. 58e41f4b71Sopenharmony_ci 59e41f4b71Sopenharmony_ci- Semaphore deletion 60e41f4b71Sopenharmony_ci 61e41f4b71Sopenharmony_ci Set a semaphore in use to the unused state and add it to the linked list of unused semaphores. 62e41f4b71Sopenharmony_ci 63e41f4b71Sopenharmony_ciThe following figure illustrates the semaphore working mechanism. 64e41f4b71Sopenharmony_ci 65e41f4b71Sopenharmony_ci**Figure 1** Semaphore working mechanism for the small system 66e41f4b71Sopenharmony_ci 67e41f4b71Sopenharmony_ci 68e41f4b71Sopenharmony_ci 69e41f4b71Sopenharmony_ci 70e41f4b71Sopenharmony_ci## Development Guidelines 71e41f4b71Sopenharmony_ci 72e41f4b71Sopenharmony_ci 73e41f4b71Sopenharmony_ci### Available APIs 74e41f4b71Sopenharmony_ci 75e41f4b71Sopenharmony_ci**Table 1** APIs for creating and deleting a semaphore 76e41f4b71Sopenharmony_ci 77e41f4b71Sopenharmony_ci| API| Description| 78e41f4b71Sopenharmony_ci| -------- | -------- | 79e41f4b71Sopenharmony_ci| LOS_SemCreate | Creates a semaphore and returns the semaphore ID.| 80e41f4b71Sopenharmony_ci| LOS_BinarySemCreate | Creates a binary semaphore. The maximum counter value is **1**.| 81e41f4b71Sopenharmony_ci| LOS_SemDelete | Deletes a semaphore.| 82e41f4b71Sopenharmony_ci 83e41f4b71Sopenharmony_ci**Table 2** APIs for requesting and releasing a semaphore 84e41f4b71Sopenharmony_ci 85e41f4b71Sopenharmony_ci| API| Description| 86e41f4b71Sopenharmony_ci| -------- | -------- | 87e41f4b71Sopenharmony_ci| LOS_SemPend | Requests a semaphore and sets a timeout period.| 88e41f4b71Sopenharmony_ci| LOS_SemPost | Releases a semaphore.| 89e41f4b71Sopenharmony_ci 90e41f4b71Sopenharmony_ci 91e41f4b71Sopenharmony_ci### How to Develop 92e41f4b71Sopenharmony_ci 93e41f4b71Sopenharmony_ci1. Call **LOS_SemCreate** to create a semaphore. To create a binary semaphore, call **LOS_BinarySemCreate**. 94e41f4b71Sopenharmony_ci 95e41f4b71Sopenharmony_ci2. Call **LOS_SemPend** to request a semaphore. 96e41f4b71Sopenharmony_ci 97e41f4b71Sopenharmony_ci3. Call **LOS_SemPost** to release a semaphore. 98e41f4b71Sopenharmony_ci 99e41f4b71Sopenharmony_ci4. Call **LOS_SemDelete** to delete a semaphore. 100e41f4b71Sopenharmony_ci 101e41f4b71Sopenharmony_ci> **NOTE**<br> 102e41f4b71Sopenharmony_ci> As interrupts cannot be blocked, semaphores cannot be requested in block mode for interrupts. 103e41f4b71Sopenharmony_ci 104e41f4b71Sopenharmony_ci 105e41f4b71Sopenharmony_ci### Development Example 106e41f4b71Sopenharmony_ci 107e41f4b71Sopenharmony_ci 108e41f4b71Sopenharmony_ci### Example Description 109e41f4b71Sopenharmony_ci 110e41f4b71Sopenharmony_ciThis example implements the following: 111e41f4b71Sopenharmony_ci 112e41f4b71Sopenharmony_ci1. 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**. 113e41f4b71Sopenharmony_ci 114e41f4b71Sopenharmony_ci2. Enable **ExampleSemTask2** to enter sleep mode for 20 ticks after acquiring the semaphore. (When **ExampleSemTask2** is delayed, **ExampleSemTask1** is woken up.) 115e41f4b71Sopenharmony_ci 116e41f4b71Sopenharmony_ci3. 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.) 117e41f4b71Sopenharmony_ci 118e41f4b71Sopenharmony_ci4. 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. 119e41f4b71Sopenharmony_ci 120e41f4b71Sopenharmony_ci5. Task **ExampleSem** is woken up after 400 ticks. After that, delete the semaphore. 121e41f4b71Sopenharmony_ci 122e41f4b71Sopenharmony_ci 123e41f4b71Sopenharmony_ci### Sample Code 124e41f4b71Sopenharmony_ci 125e41f4b71Sopenharmony_ciThe sample code can be compiled and verified in **./kernel/liteos_a/testsuites/kernel/src/osTest.c**. The **ExampleSem** function is called in **TestTaskEntry**. 126e41f4b71Sopenharmony_ci 127e41f4b71Sopenharmony_ciThe sample code is as follows: 128e41f4b71Sopenharmony_ci 129e41f4b71Sopenharmony_ci``` 130e41f4b71Sopenharmony_ci#include "los_sem.h" 131e41f4b71Sopenharmony_ci#include "securec.h" 132e41f4b71Sopenharmony_ci 133e41f4b71Sopenharmony_ci/* Task ID*/ 134e41f4b71Sopenharmony_cistatic UINT32 g_testTaskId01; 135e41f4b71Sopenharmony_cistatic UINT32 g_testTaskId02; 136e41f4b71Sopenharmony_ci 137e41f4b71Sopenharmony_ci/* Task priority */ 138e41f4b71Sopenharmony_ci#define TASK_PRIO_LOW 5 139e41f4b71Sopenharmony_ci#define TASK_PRIO_HI 4 140e41f4b71Sopenharmony_ci 141e41f4b71Sopenharmony_ci/* Semaphore structure ID */ 142e41f4b71Sopenharmony_cistatic UINT32 g_semId; 143e41f4b71Sopenharmony_ci 144e41f4b71Sopenharmony_ciVOID ExampleSemTask1(VOID) 145e41f4b71Sopenharmony_ci{ 146e41f4b71Sopenharmony_ci UINT32 ret; 147e41f4b71Sopenharmony_ci 148e41f4b71Sopenharmony_ci dprintf("ExampleSemTask1 try get sem g_semId, timeout 10 ticks.\n"); 149e41f4b71Sopenharmony_ci 150e41f4b71Sopenharmony_ci /* Request the semaphore in scheduled block mode, with a wait timeout period of 10 ticks. */ 151e41f4b71Sopenharmony_ci ret = LOS_SemPend(g_semId, 10); 152e41f4b71Sopenharmony_ci /* The semaphore is acquired. */ 153e41f4b71Sopenharmony_ci if (ret == LOS_OK) { 154e41f4b71Sopenharmony_ci LOS_SemPost(g_semId); 155e41f4b71Sopenharmony_ci return; 156e41f4b71Sopenharmony_ci } 157e41f4b71Sopenharmony_ci /* The semaphore is not acquired when the timeout period has expired. */ 158e41f4b71Sopenharmony_ci if (ret == LOS_ERRNO_SEM_TIMEOUT) { 159e41f4b71Sopenharmony_ci dprintf("ExampleSemTask1 timeout and try get sem g_semId wait forever.\n"); 160e41f4b71Sopenharmony_ci 161e41f4b71Sopenharmony_ci /* Request the semaphore in permanent block mode. */ 162e41f4b71Sopenharmony_ci ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER); 163e41f4b71Sopenharmony_ci dprintf("ExampleSemTask1 wait_forever and get sem g_semId.\n"); 164e41f4b71Sopenharmony_ci if (ret == LOS_OK) { 165e41f4b71Sopenharmony_ci dprintf("ExampleSemTask1 post sem g_semId.\n"); 166e41f4b71Sopenharmony_ci LOS_SemPost(g_semId); 167e41f4b71Sopenharmony_ci return; 168e41f4b71Sopenharmony_ci } 169e41f4b71Sopenharmony_ci } 170e41f4b71Sopenharmony_ci} 171e41f4b71Sopenharmony_ci 172e41f4b71Sopenharmony_ciVOID ExampleSemTask2(VOID) 173e41f4b71Sopenharmony_ci{ 174e41f4b71Sopenharmony_ci UINT32 ret; 175e41f4b71Sopenharmony_ci dprintf("ExampleSemTask2 try get sem g_semId wait forever.\n"); 176e41f4b71Sopenharmony_ci 177e41f4b71Sopenharmony_ci /* Request the semaphore in permanent block mode. */ 178e41f4b71Sopenharmony_ci ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER); 179e41f4b71Sopenharmony_ci if (ret == LOS_OK) { 180e41f4b71Sopenharmony_ci dprintf("ExampleSemTask2 get sem g_semId and then delay 20 ticks.\n"); 181e41f4b71Sopenharmony_ci } 182e41f4b71Sopenharmony_ci 183e41f4b71Sopenharmony_ci /* Enable the task to enter sleep mode for 20 ticks. */ 184e41f4b71Sopenharmony_ci LOS_TaskDelay(20); 185e41f4b71Sopenharmony_ci 186e41f4b71Sopenharmony_ci dprintf("ExampleSemTask2 post sem g_semId.\n"); 187e41f4b71Sopenharmony_ci /* Release the semaphore. */ 188e41f4b71Sopenharmony_ci LOS_SemPost(g_semId); 189e41f4b71Sopenharmony_ci return; 190e41f4b71Sopenharmony_ci} 191e41f4b71Sopenharmony_ci 192e41f4b71Sopenharmony_ciUINT32 ExampleSem(VOID) 193e41f4b71Sopenharmony_ci{ 194e41f4b71Sopenharmony_ci UINT32 ret; 195e41f4b71Sopenharmony_ci TSK_INIT_PARAM_S task1; 196e41f4b71Sopenharmony_ci TSK_INIT_PARAM_S task2; 197e41f4b71Sopenharmony_ci 198e41f4b71Sopenharmony_ci /* Create a semaphore. */ 199e41f4b71Sopenharmony_ci LOS_SemCreate(0, &g_semId); 200e41f4b71Sopenharmony_ci 201e41f4b71Sopenharmony_ci /* Lock task scheduling. */ 202e41f4b71Sopenharmony_ci LOS_TaskLock(); 203e41f4b71Sopenharmony_ci 204e41f4b71Sopenharmony_ci /* Create task 1. */ 205e41f4b71Sopenharmony_ci (VOID)memset_s(&task1, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S)); 206e41f4b71Sopenharmony_ci task1.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask1; 207e41f4b71Sopenharmony_ci task1.pcName = "TestTask1"; 208e41f4b71Sopenharmony_ci task1.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; 209e41f4b71Sopenharmony_ci task1.usTaskPrio = TASK_PRIO_LOW; 210e41f4b71Sopenharmony_ci ret = LOS_TaskCreate(&g_testTaskId01, &task1); 211e41f4b71Sopenharmony_ci if (ret != LOS_OK) { 212e41f4b71Sopenharmony_ci dprintf("task1 create failed .\n"); 213e41f4b71Sopenharmony_ci return LOS_NOK; 214e41f4b71Sopenharmony_ci } 215e41f4b71Sopenharmony_ci 216e41f4b71Sopenharmony_ci /* Create task 2. */ 217e41f4b71Sopenharmony_ci (VOID)memset_s(&task2, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S)); 218e41f4b71Sopenharmony_ci task2.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask2; 219e41f4b71Sopenharmony_ci task2.pcName = "TestTask2"; 220e41f4b71Sopenharmony_ci task2.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; 221e41f4b71Sopenharmony_ci task2.usTaskPrio = TASK_PRIO_HI; 222e41f4b71Sopenharmony_ci ret = LOS_TaskCreate(&g_testTaskId02, &task2); 223e41f4b71Sopenharmony_ci if (ret != LOS_OK) { 224e41f4b71Sopenharmony_ci dprintf("task2 create failed.\n"); 225e41f4b71Sopenharmony_ci return LOS_NOK; 226e41f4b71Sopenharmony_ci } 227e41f4b71Sopenharmony_ci 228e41f4b71Sopenharmony_ci /* Unlock task scheduling. */ 229e41f4b71Sopenharmony_ci LOS_TaskUnlock(); 230e41f4b71Sopenharmony_ci 231e41f4b71Sopenharmony_ci /* Enable the task to enter sleep mode for 400 ticks. */ 232e41f4b71Sopenharmony_ci LOS_TaskDelay(400); 233e41f4b71Sopenharmony_ci 234e41f4b71Sopenharmony_ci ret = LOS_SemPost(g_semId); 235e41f4b71Sopenharmony_ci 236e41f4b71Sopenharmony_ci /* Enable the task to enter sleep mode for 400 ticks. */ 237e41f4b71Sopenharmony_ci LOS_TaskDelay(400); 238e41f4b71Sopenharmony_ci 239e41f4b71Sopenharmony_ci /* Delete the semaphore. */ 240e41f4b71Sopenharmony_ci LOS_SemDelete(g_semId); 241e41f4b71Sopenharmony_ci return LOS_OK; 242e41f4b71Sopenharmony_ci} 243e41f4b71Sopenharmony_ci``` 244e41f4b71Sopenharmony_ci 245e41f4b71Sopenharmony_ci 246e41f4b71Sopenharmony_ci### Verification 247e41f4b71Sopenharmony_ci 248e41f4b71Sopenharmony_ciThe development is successful if the return result is as follows: 249e41f4b71Sopenharmony_ci 250e41f4b71Sopenharmony_ci 251e41f4b71Sopenharmony_ci``` 252e41f4b71Sopenharmony_ciExampleSemTask2 try get sem g_semId wait forever. 253e41f4b71Sopenharmony_ciExampleSemTask1 try get sem g_semId, timeout 10 ticks. 254e41f4b71Sopenharmony_ciExampleSemTask1 timeout and try get sem g_semId wait forever. 255e41f4b71Sopenharmony_ciExampleSemTask2 get sem g_semId and then delay 20 ticks. 256e41f4b71Sopenharmony_ciExampleSemTask2 post sem g_semId. 257e41f4b71Sopenharmony_ciExampleSemTask1 wait_forever and get sem g_semId. 258e41f4b71Sopenharmony_ciExampleSemTask1 post sem g_semId. 259e41f4b71Sopenharmony_ci``` 260