• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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