• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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![](figure/semaphore-working-mechanism-22.png "semaphore-working-mechanism-22")
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>![](../public_sys-resources/icon-note.gif) **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