• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Semaphore
2
3## Basic Concepts
4
5Semaphore is a mechanism for implementing communication between tasks. It implements synchronization between tasks or exclusive access to shared resources.
6
7In the data structure of a semaphore, there is usually a counter value indicating the available resources. The counter value can be:
8
9-   **0**: The semaphore is unavailable. In this case, tasks waiting for the semaphore may exist.
10-   Positive number: The semaphore is available.
11
12The usage of the counter value varies with the function of the semaphore.
13
14-   If the semaphore is used as a mutex, 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.
15-   If the semaphore is used for synchronization, the initial semaphore counter value is  **0**. When a task fails to acquire the semaphore, it will be blocked and enters Ready or Running state only when the semaphore is released. In this way, task synchronization is implemented.
16
17## Working Principles
18
19### Semaphore control block
20
21```
22/**
23 * Data structure of the semaphore control block
24 */
25typedef struct {
26    UINT16            semStat;          /* Semaphore status */
27    UINT16            semType;          /* Semaphore type */
28    UINT16            semCount;         /* Semaphore count */
29    UINT16            semId;            /* Semaphore index */
30    LOS_DL_LIST       semList;          /* Insert the task blocked by the semaphore to the DL list.*/
31} LosSemCB;
32```
33
34### Working Principles
35
36Initializing semaphores: Request memory for the semaphores configured \(the number of semaphores can be configured in the  **LOSCFG\_BASE\_IPC\_SEM\_LIMIT**  macro by users\), set all semaphores to the unused state, and add them to the linked list for unused semaphores.
37
38Creating a semaphore: Obtain a semaphore from the linked list for unused semaphores and set its initial value.
39
40Requesting a semaphore: If the counter value is greater than  **0**, the system allocates a semaphore, decreases the counter value by 1, and returns a success message. If the counter value is  **0**, the task is blocked and waits for other tasks to release a semaphore. The waiting timeout period can be set. When a task is blocked by a semaphore, the task will be added to the end of the semaphore waiting task queue.
41
42Releasing a semaphore: If there is no task waiting for the semaphore released, the counter is incremented by 1. Otherwise, wake up the first task in the semaphore waiting queue.
43
44Deleting a semaphore: Set the semaphore in use to the unused state, and adds it to the linked list for unused semaphores.
45
46A semaphore can also be used to limit the number of tasks that can access the shared resource at the same time. When the number of tasks accessing the resource reaches the limit, other tasks will be blocked until a task releases the semaphore.
47
48**Figure  1**  Semaphore working mechanism for mini systems<a name="fig467314634214"></a>
49![](figures/semaphore-working-mechanism-for-mini-systems.png "semaphore-working-mechanism-for-mini-systems")
50
51## Available APIs
52
53<a name="table1078714915105"></a>
54<table><thead align="left"><tr id="row1280518971010"><th class="cellrowborder" valign="top" width="20.1%" id="mcps1.1.4.1.1"><p id="p1380510912104"><a name="p1380510912104"></a><a name="p1380510912104"></a>Function</p>
55</th>
56<th class="cellrowborder" valign="top" width="20.52%" id="mcps1.1.4.1.2"><p id="p08051291106"><a name="p08051291106"></a><a name="p08051291106"></a>API</p>
57</th>
58<th class="cellrowborder" valign="top" width="59.38%" id="mcps1.1.4.1.3"><p id="p12805149151012"><a name="p12805149151012"></a><a name="p12805149151012"></a>Description</p>
59</th>
60</tr>
61</thead>
62<tbody><tr id="row168052913104"><td class="cellrowborder" rowspan="3" valign="top" width="20.1%" headers="mcps1.1.4.1.1 "><p id="p180618915101"><a name="p180618915101"></a><a name="p180618915101"></a>Creating or deleting a semaphore</p>
63</td>
64<td class="cellrowborder" valign="top" width="20.52%" headers="mcps1.1.4.1.2 "><p id="p198061196105"><a name="p198061196105"></a><a name="p198061196105"></a>LOS_SemCreate</p>
65</td>
66<td class="cellrowborder" valign="top" width="59.38%" headers="mcps1.1.4.1.3 "><p id="p1980609121010"><a name="p1980609121010"></a><a name="p1980609121010"></a>Creates a semaphore and returns the semaphore ID.</p>
67</td>
68</tr>
69<tr id="row4806990105"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p280620917109"><a name="p280620917109"></a><a name="p280620917109"></a>LOS_BinarySemCreate</p>
70</td>
71<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p780614919107"><a name="p780614919107"></a><a name="p780614919107"></a>Creates a binary semaphore. The maximum counter value is <strong id="b19111879045016"><a name="b19111879045016"></a><a name="b19111879045016"></a>1</strong>.</p>
72</td>
73</tr>
74<tr id="row17806159151018"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p38067931012"><a name="p38067931012"></a><a name="p38067931012"></a>LOS_SemDelete</p>
75</td>
76<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p168063941015"><a name="p168063941015"></a><a name="p168063941015"></a>Deletes a semaphore.</p>
77</td>
78</tr>
79<tr id="row188061098102"><td class="cellrowborder" rowspan="2" valign="top" width="20.1%" headers="mcps1.1.4.1.1 "><p id="p5806179161014"><a name="p5806179161014"></a><a name="p5806179161014"></a>Requesting or releasing a semaphore</p>
80</td>
81<td class="cellrowborder" valign="top" width="20.52%" headers="mcps1.1.4.1.2 "><p id="p16806159201015"><a name="p16806159201015"></a><a name="p16806159201015"></a>LOS_SemPend</p>
82</td>
83<td class="cellrowborder" valign="top" width="59.38%" headers="mcps1.1.4.1.3 "><p id="p4806149191011"><a name="p4806149191011"></a><a name="p4806149191011"></a>Requests a specified semaphore and sets the timeout period.</p>
84</td>
85</tr>
86<tr id="row4806199141019"><td class="cellrowborder" valign="top" headers="mcps1.1.4.1.1 "><p id="p280618913105"><a name="p280618913105"></a><a name="p280618913105"></a>LOS_SemPost</p>
87</td>
88<td class="cellrowborder" valign="top" headers="mcps1.1.4.1.2 "><p id="p178061917109"><a name="p178061917109"></a><a name="p178061917109"></a>Posts (releases) a semaphore.</p>
89</td>
90</tr>
91</tbody>
92</table>
93
94## How to Develop
95
961.  Call  **LOS\_SemCreate**  to create a semaphore. To create a binary semaphore, call  **LOS\_BinarySemCreate**.
972.  Call  **LOS\_SemPend**  to request a semaphore.
983.  Call  **LOS\_SemPost**  to release a semaphore.
994.  Call  **LOS\_SemDelete**  to delete a semaphore.
100
101>![](../public_sys-resources/icon-note.gif) **NOTE:**
102>As interrupts cannot be blocked, semaphores cannot be requested in block mode for interrupts.
103
104## Development Example
105
106### Example Description
107
108This example implements the following:
109
1101.  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**.
1112.  Enable** ExampleSemTask2**  to enter sleep mode for 20 ticks after acquiring the semaphore. \(When  **ExampleSemTask2**  is delayed,  **ExampleSemTask1**  is woken up.\)
1123.  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.\)
1134.  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.
1145.  Task  **ExampleSem**  is woken up after 400 ticks and deletes the semaphore.
115
116### Sample Code
117
118The sample code is as follows:
119
120```
121#include "los_sem.h"
122#include "securec.h"
123
124/* Task ID*/
125static UINT32 g_testTaskId01;
126static UINT32 g_testTaskId02;
127
128/* Task priority */
129#define TASK_PRIO_TEST  5
130
131/* Semaphore structure ID */
132static UINT32 g_semId;
133
134VOID ExampleSemTask1(VOID)
135{
136    UINT32 ret;
137
138    printf("ExampleSemTask1 try get sem g_semId, timeout 10 ticks.\n");
139
140    /* Request the semaphore in scheduled block mode, with a wait timeout period of 10 ticks. */
141    ret = LOS_SemPend(g_semId, 10);
142
143    /* The semaphore is acquired. */
144    if (ret == LOS_OK) {
145         LOS_SemPost(g_semId);
146         return;
147    }
148    /* The semaphore is not acquired when the timeout period has expired. */
149    if (ret == LOS_ERRNO_SEM_TIMEOUT) {
150        printf("ExampleSemTask1 timeout and try get sem g_semId wait forever.\n");
151
152        /* Request the semaphore in permanent block mode. */
153        ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER);
154        printf("ExampleSemTask1 wait_forever and get sem g_semId.\n");
155        if (ret == LOS_OK) {
156            LOS_SemPost(g_semId);
157            return;
158        }
159    }
160}
161
162VOID ExampleSemTask2(VOID)
163{
164    UINT32 ret;
165    printf("ExampleSemTask2 try get sem g_semId wait forever.\n");
166
167    /* Request the semaphore in permanent block mode. */
168    ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER);
169
170    if (ret == LOS_OK) {
171        printf("ExampleSemTask2 get sem g_semId and then delay 20 ticks.\n");
172    }
173
174  /* Enable the task to enter sleep mode for 20 ticks. */
175    LOS_TaskDelay(20);
176
177    printf("ExampleSemTask2 post sem g_semId.\n");
178    /* Release the semaphore. */
179    LOS_SemPost(g_semId);
180    return;
181}
182
183UINT32 ExampleSem(VOID)
184{
185    UINT32 ret;
186    TSK_INIT_PARAM_S task1;
187    TSK_INIT_PARAM_S task2;
188
189   /* Create a semaphore. */
190    LOS_SemCreate(0, &g_semId);
191
192    /* Lock task scheduling. */
193    LOS_TaskLock();
194
195    /* Create task 1. */
196    (VOID)memset_s(&task1, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
197    task1.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask1;
198    task1.pcName       = "TestTask1";
199    task1.uwStackSize  = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
200    task1.usTaskPrio   = TASK_PRIO_TEST;
201    ret = LOS_TaskCreate(&g_testTaskId01, &task1);
202    if (ret != LOS_OK) {
203        printf("task1 create failed.\n");
204        return LOS_NOK;
205    }
206
207    /* Create task 2. */
208    (VOID)memset_s(&task2, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
209    task2.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask2;
210    task2.pcName       = "TestTask2";
211    task2.uwStackSize  = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
212    task2.usTaskPrio   = (TASK_PRIO_TEST - 1);
213    ret = LOS_TaskCreate(&g_testTaskId02, &task2);
214    if (ret != LOS_OK) {
215        printf("task2 create failed.\n");
216        return LOS_NOK;
217    }
218
219    /* Unlock task scheduling. */
220    LOS_TaskUnlock();
221
222    ret = LOS_SemPost(g_semId);
223
224 /* Enable the task to enter sleep mode for 400 ticks. */
225    LOS_TaskDelay(400);
226
227 /* Delete the semaphore. */
228    LOS_SemDelete(g_semId);
229    return LOS_OK;
230}
231```
232
233### Verification
234
235The development is successful if the return result is as follows:
236
237```
238ExampleSemTask2 try get sem g_semId wait forever.
239ExampleSemTask2 get sem g_semId and then delay 20 ticks.
240ExampleSemTask1 try get sem g_semId, timeout 10 ticks.
241
242ExampleSemTask1 timeout and try get sem g_semId wait forever.
243ExampleSemTask2 post sem g_semId.
244ExampleSemTask1 wait_forever and get sem g_semId.
245```
246
247