kernel-small-basic-trans-semaphore.md 9.1 KB
Newer Older
A
Annie_wang 已提交
1
# Semaphore
D
duangavin123 已提交
2 3


A
Annie_wang 已提交
4
## Basic Concepts
D
duangavin123 已提交
5

A
Annie_wang 已提交
6
Semaphore is a mechanism used to implement synchronization between tasks or exclusive access to shared resources.
D
duangavin123 已提交
7

A
Annie_wang 已提交
8
In the semaphore data structure, there is a value indicating the number of shared resources available. The value can be:
D
duangavin123 已提交
9

A
Annie_wang 已提交
10
- **0**: The semaphore is unavailable. In this case, tasks waiting for the semaphore may exist.
D
duangavin123 已提交
11

A
Annie_wang 已提交
12
- Positive number: The semaphore is available.
D
duangavin123 已提交
13

A
Annie_wang 已提交
14
The semaphore used for exclusive access to resources is different from the semaphore used for synchronization:
D
duangavin123 已提交
15

A
Annie_wang 已提交
16 17 18 19 20 21
-   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.

-   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.


## Working Principles
D
duangavin123 已提交
22

D
duangavin123 已提交
23
**Semaphore Control Block**
D
duangavin123 已提交
24

A
Annie_wang 已提交
25

D
duangavin123 已提交
26 27
```
/**
A
Annie_wang 已提交
28
  * Data structure of the semaphore control block
D
duangavin123 已提交
29 30 31
 */
typedef struct {
    UINT16            semStat;          /* Semaphore status */
A
Annie_wang 已提交
32 33 34 35
    UINT16            semType;          /* Semaphore type */
    UINT16            semCount;         /* Semaphore count */
    UINT16            semId;            /* Semaphore ID */
    LOS_DL_LIST       semList;          /* List of blocked tasks */
D
duangavin123 已提交
36 37 38
} LosSemCB;
```

D
duangavin123 已提交
39
**Working Principles**
D
duangavin123 已提交
40 41 42

Semaphore 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.

A
Annie_wang 已提交
43 44 45 46 47 48 49
- Semaphore initialization
  
  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.
  
- Semaphore creation

  Obtain a semaphore from the linked list of unused semaphores and assign an initial value to the semaphore.
D
duangavin123 已提交
50

A
Annie_wang 已提交
51
- Semaphore request
D
duangavin123 已提交
52

A
Annie_wang 已提交
53
  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.
D
duangavin123 已提交
54

A
Annie_wang 已提交
55
- Semaphore release
D
duangavin123 已提交
56

A
Annie_wang 已提交
57
  If no task is waiting for the semaphore, the counter is incremented by 1. Otherwise, wake up the first task in the wait queue.
D
duangavin123 已提交
58

A
Annie_wang 已提交
59
- Semaphore deletion
D
duangavin123 已提交
60

A
Annie_wang 已提交
61
  Set a semaphore in use to the unused state and add it to the linked list of unused semaphores.
D
duangavin123 已提交
62

A
Annie_wang 已提交
63
The following figure illustrates the semaphore working mechanism.
D
duangavin123 已提交
64

A
Annie_wang 已提交
65
**Figure 1** Semaphore working mechanism for the small system
D
duangavin123 已提交
66

A
Annie_wang 已提交
67
![](figures/semaphore-working-mechanism-for-small-systems.png "semaphore-working-mechanism-for-small-systems")
D
duangavin123 已提交
68 69


A
Annie_wang 已提交
70
## Development Guidelines
D
duangavin123 已提交
71 72


A
Annie_wang 已提交
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
### Available APIs

**Table 1** APIs for creating and deleting a semaphore

| API| Description|
| -------- | -------- |
| LOS_SemCreate | Creates a semaphore and returns the semaphore ID.|
| LOS_BinarySemCreate | Creates a binary semaphore. The maximum counter value is **1**.|
| LOS_SemDelete | Deletes a semaphore.|

**Table 2** APIs for requesting and releasing a semaphore

| API| Description|
| -------- | -------- |
| LOS_SemPend | Requests a semaphore and sets a timeout period.|
| LOS_SemPost | Releases a semaphore.|


### How to Develop

1. Call **LOS_SemCreate** to create a semaphore. To create a binary semaphore, call **LOS_BinarySemCreate**.

2. Call **LOS_SemPend** to request a semaphore.

3. Call **LOS_SemPost** to release a semaphore.

4. Call **LOS_SemDelete** to delete a semaphore.

> **NOTE**<br>
> As interrupts cannot be blocked, semaphores cannot be requested in block mode for interrupts.


### Development Example


### Example Description
D
duangavin123 已提交
109 110 111

This example implements the following:

A
Annie_wang 已提交
112 113 114 115 116 117 118 119 120 121 122 123
1. 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**.

2. Enable **ExampleSemTask2** to enter sleep mode for 20 ticks after acquiring the semaphore. (When **ExampleSemTask2** is delayed, **ExampleSemTask1** is woken up.)

3. 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.)

4. 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.

5. Task **ExampleSem** is woken up after 400 ticks. After that, delete the semaphore.


### Sample Code
D
duangavin123 已提交
124

A
Annie_wang 已提交
125
The sample code can be compiled and verified in **./kernel/liteos_a/testsuites/kernel/src/osTest.c**. The **ExampleSem** function is called in **TestTaskEntry**.
D
duangavin123 已提交
126 127 128 129 130 131 132 133 134 135 136 137

The sample code is as follows:

```
#include "los_sem.h"
#include "securec.h"

/* Task ID*/
static UINT32 g_testTaskId01;
static UINT32 g_testTaskId02;

/* Task priority */
A
Annie_wang 已提交
138 139
#define TASK_PRIO_LOW   5
#define TASK_PRIO_HI    4
D
duangavin123 已提交
140

A
Annie_wang 已提交
141
/* Semaphore structure ID */
D
duangavin123 已提交
142 143 144 145 146 147
static UINT32 g_semId;

VOID ExampleSemTask1(VOID)
{
    UINT32 ret;

A
Annie_wang 已提交
148
    dprintf("ExampleSemTask1 try get sem g_semId, timeout 10 ticks.\n");
D
duangavin123 已提交
149

A
Annie_wang 已提交
150
    /* Request the semaphore in scheduled block mode, with a wait timeout period of 10 ticks. */
D
duangavin123 已提交
151
    ret = LOS_SemPend(g_semId, 10);
A
Annie_wang 已提交
152
    /* The semaphore is acquired. */
D
duangavin123 已提交
153 154 155 156
    if (ret == LOS_OK) {
         LOS_SemPost(g_semId);
         return;
    }
A
Annie_wang 已提交
157
    /* The semaphore is not acquired when the timeout period has expired. */
D
duangavin123 已提交
158
    if (ret == LOS_ERRNO_SEM_TIMEOUT) {
A
Annie_wang 已提交
159
        dprintf("ExampleSemTask1 timeout and try get sem g_semId wait forever.\n");
D
duangavin123 已提交
160

A
Annie_wang 已提交
161
        /* Request the semaphore in permanent block mode. */
D
duangavin123 已提交
162
        ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER);
A
Annie_wang 已提交
163
        dprintf("ExampleSemTask1 wait_forever and get sem g_semId.\n");
D
duangavin123 已提交
164
        if (ret == LOS_OK) {
A
Annie_wang 已提交
165
            dprintf("ExampleSemTask1 post sem g_semId.\n");
D
duangavin123 已提交
166 167 168 169 170 171 172 173 174
            LOS_SemPost(g_semId);
            return;
        }
    }
}

VOID ExampleSemTask2(VOID)
{
    UINT32 ret;
A
Annie_wang 已提交
175
    dprintf("ExampleSemTask2 try get sem g_semId wait forever.\n");
D
duangavin123 已提交
176

A
Annie_wang 已提交
177
    /* Request the semaphore in permanent block mode. */
D
duangavin123 已提交
178 179
    ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER);
    if (ret == LOS_OK) {
A
Annie_wang 已提交
180
        dprintf("ExampleSemTask2 get sem g_semId and then delay 20 ticks.\n");
D
duangavin123 已提交
181 182
    }

A
Annie_wang 已提交
183
    /* Enable the task to enter sleep mode for 20 ticks. */
D
duangavin123 已提交
184 185
    LOS_TaskDelay(20);

A
Annie_wang 已提交
186 187
    dprintf("ExampleSemTask2 post sem g_semId.\n");
    /* Release the semaphore. */
D
duangavin123 已提交
188 189 190 191 192 193 194 195 196 197
    LOS_SemPost(g_semId);
    return;
}

UINT32 ExampleSem(VOID)
{
    UINT32 ret;
    TSK_INIT_PARAM_S task1;
    TSK_INIT_PARAM_S task2;

A
Annie_wang 已提交
198
   /* Create a semaphore. */
D
duangavin123 已提交
199 200
    LOS_SemCreate(0, &g_semId);

A
Annie_wang 已提交
201
    /* Lock task scheduling. */
D
duangavin123 已提交
202 203
    LOS_TaskLock();

A
Annie_wang 已提交
204
    /* Create task 1. */
D
duangavin123 已提交
205 206 207 208
    (VOID)memset_s(&task1, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
    task1.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask1;
    task1.pcName       = "TestTask1";
    task1.uwStackSize  = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
A
Annie_wang 已提交
209
    task1.usTaskPrio   = TASK_PRIO_LOW;
D
duangavin123 已提交
210 211
    ret = LOS_TaskCreate(&g_testTaskId01, &task1);
    if (ret != LOS_OK) {
A
Annie_wang 已提交
212
        dprintf("task1 create failed .\n");
D
duangavin123 已提交
213 214 215
        return LOS_NOK;
    }

A
Annie_wang 已提交
216
    /* Create task 2. */
D
duangavin123 已提交
217 218 219 220
    (VOID)memset_s(&task2, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
    task2.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask2;
    task2.pcName       = "TestTask2";
    task2.uwStackSize  = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
A
Annie_wang 已提交
221
    task2.usTaskPrio   = TASK_PRIO_HI;
D
duangavin123 已提交
222 223
    ret = LOS_TaskCreate(&g_testTaskId02, &task2);
    if (ret != LOS_OK) {
A
Annie_wang 已提交
224
        dprintf("task2 create failed.\n");
D
duangavin123 已提交
225 226 227
        return LOS_NOK;
    }

A
Annie_wang 已提交
228
    /* Unlock task scheduling. */
D
duangavin123 已提交
229 230
    LOS_TaskUnlock();

A
Annie_wang 已提交
231 232 233
     /* Enable the task to enter sleep mode for 400 ticks. */
    LOS_TaskDelay(400);

D
duangavin123 已提交
234 235
    ret = LOS_SemPost(g_semId);

A
Annie_wang 已提交
236
     /* Enable the task to enter sleep mode for 400 ticks. */
D
duangavin123 已提交
237 238
    LOS_TaskDelay(400);

A
Annie_wang 已提交
239
    /* Delete the semaphore. */
D
duangavin123 已提交
240 241 242 243 244
    LOS_SemDelete(g_semId);
    return LOS_OK;
}
```

A
Annie_wang 已提交
245 246

### Verification
D
duangavin123 已提交
247 248 249

The development is successful if the return result is as follows:

A
Annie_wang 已提交
250

D
duangavin123 已提交
251 252 253 254
```
ExampleSemTask2 try get sem g_semId wait forever.
ExampleSemTask1 try get sem g_semId, timeout 10 ticks.
ExampleSemTask1 timeout and try get sem g_semId wait forever.
A
Annie_wang 已提交
255
ExampleSemTask2 get sem g_semId and then delay 20 ticks.
D
duangavin123 已提交
256 257
ExampleSemTask2 post sem g_semId.
ExampleSemTask1 wait_forever and get sem g_semId.
A
Annie_wang 已提交
258
ExampleSemTask1 post sem g_semId.
D
duangavin123 已提交
259
```