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![](figures/semaphore-working-mechanism-for-small-systems.png "semaphore-working-mechanism-for-small-systems")
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