README_zh.md
1# 小凌派-RK2206开发板OpenHarmonyOS内核开发-信号量
2
3## 实验内容
4
5本例程演示如何在小凌派-RK2206开发板上使用鸿蒙LiteOS-M内核接口,通过信号量控制不同的线程,实现任务之间的同步。
6
7
8
9## 程序设计
10
11信号量是一种实现任务间通信的机制,可以实现任务间同步或共享资源的互斥访问。
12
13一个信号量的数据结构中,通常有一个计数值,用于对有效资源数的计数,表示剩下的可被使用的共享资源数,其值的含义分两种情况:
14
15* 0,表示该信号量当前不可获取,因此可能存在正在等待该信号量的任务。
16* 正值,表示该信号量当前可被获取。
17
18信号量是一种上锁机制,代码必须获得对应的钥匙才能继续执行。一旦获得了钥匙,就意味着该任务具有进入被锁部分代码的权限。一旦执行被锁代码段,则其它任务需要等待,直到被锁部分代码的钥匙被再次释放才能继续执行。任务可以利用信号量与其它任务、中断服务程序进行同步。
19
20本例程设计3个任务,任务control_thread每隔1秒释放信号量,任务sem_one_thread和sem_two_thread则不断地尝试获取信号量。
21
22### API分析
23
24**头文件:**
25
26/kernel/liteos_m/kernel/include/los_sem.h
27
28#### LOS_SemCreate()
29
30```c
31UINT32 LOS_SemCreate(UINT16 count, UINT32 *semHandle);
32```
33
34**描述:**
35
36创建信号量,返回信号量ID
37
38**参数:**
39
40| 名字 | 描述 |
41| :-------- | :--------------- |
42| count | 可用的信号量数量 |
43| semHandle | 申请的信号量指针 |
44
45**返回值:**
46
47| 返回值 | 描述 |
48| :------------------------------------------------------------------------------------- | :--- |
49| LOS_OK | 成功 |
50| LOS_ERRNO_SEM_PTR_NULL`<br>` LOS_ERRNO_SEM_OVERFLOW `<br>` LOS_ERRNO_SEM_ALL_BUSY | 失败 |
51
52#### LOS_SemDelete()
53
54```c
55UINT32 LOS_SemDelete(UINT32 semHandle);
56```
57
58**描述:**
59
60删除指定的信号量
61
62**参数:**
63
64| 名字 | 描述 |
65| :-------- | :--------------- |
66| semHandle | 需要删除的信号量 |
67
68**返回值:**
69
70| 返回值 | 描述 |
71| :------------------------------------------------------------------------------------------------------------------------------------------------------------ | :--- |
72| LOS_OK | 成功 |
73| LOS_ERRNO_SEM_INVALID`<br>` LOS_ERRNO_SEM_UNAVAILABLE `<br>` LOS_ERRNO_SEM_PEND_INTERR `<br>` LOS_ERRNO_SEM_PEND_IN_LOCK `<br>` LOS_ERRNO_SEM_TIMEOUT | 失败 |
74
75#### LOS_SemPend()
76
77```c
78UINT32 LOS_SemPend(UINT32 semHandle, UINT32 timeout);
79```
80
81**描述:**
82申请指定的信号量,并设置超时时间
83
84**参数:**
85
86| 名字 | 描述 |
87| :-------- | :--------------- |
88| semHandle | 需要申请的信号量 |
89| timeout | 超时时间 |
90
91**返回值:**
92
93| 返回值 | 描述 |
94| :------------------------------------------------------------------------------------------------------------------------------------------------------------ | :--- |
95| LOS_OK | 成功 |
96| LOS_ERRNO_SEM_INVALID`<br>` LOS_ERRNO_SEM_UNAVAILABLE `<br>` LOS_ERRNO_SEM_PEND_INTERR `<br>` LOS_ERRNO_SEM_PEND_IN_LOCK `<br>` LOS_ERRNO_SEM_TIMEOUT | 失败 |
97
98#### LOS_SemPost()
99
100```c
101UINT32 LOS_SemPost(UINT32 semHandle);
102```
103
104**描述:**
105释放指定的信号量
106
107**参数:**
108
109| 名字 | 描述 |
110| :-------- | :--------------- |
111| semHandle | 需要释放的信号量 |
112
113**返回值:**
114
115| 返回值 | 描述 |
116| :--------------------------------------------------- | :--- |
117| LOS_OK | 成功 |
118| LOS_ERRNO_SEM_INVALID`<br>` LOS_ERRNO_SEM_OVERFLOW | 失败 |
119
120### 软件设计
121
122**主要代码分析**
123
124在semaphore_example函数中,通过LOS_SemCreate函数创建m_sem信号量,并通过LOS_TaskCreate函数创建三个线程:control_thread、sem_one_thread和sem_two_thread。
125
126```c
127void semaphore_example()
128{
129 unsigned int thread_crtl;
130 unsigned int thread_id1;
131 unsigned int thread_id2;
132 TSK_INIT_PARAM_S task1 = {0};
133 TSK_INIT_PARAM_S task2 = {0};
134 TSK_INIT_PARAM_S task3 = {0};
135 unsigned int ret = LOS_OK;
136
137 ret = LOS_SemCreate(MAX_COUNT, &m_sem);
138 if (ret != LOS_OK)
139 {
140 printf("Failed to create Semaphore\n");
141 return;
142 }
143
144 task1.pfnTaskEntry = (TSK_ENTRY_FUNC)control_thread;
145 task1.uwStackSize = 2048;
146 task1.pcName = "control_thread";
147 task1.usTaskPrio = 24;
148 ret = LOS_TaskCreate(&thread_crtl, &task1);
149 if (ret != LOS_OK)
150 {
151 printf("Failed to create control_thread ret:0x%x\n", ret);
152 return;
153 }
154
155 task2.pfnTaskEntry = (TSK_ENTRY_FUNC)sem_one_thread;
156 task2.uwStackSize = 2048;
157 task2.pcName = "sem_one_thread";
158 task2.usTaskPrio = 24;
159 ret = LOS_TaskCreate(&thread_id1, &task2);
160 if (ret != LOS_OK)
161 {
162 printf("Failed to create sem_one_thread ret:0x%x\n", ret);
163 return;
164 }
165
166 task3.pfnTaskEntry = (TSK_ENTRY_FUNC)sem_two_thread;
167 task3.uwStackSize = 2048;
168 task3.pcName = "sem_two_thread";
169 task3.usTaskPrio = 24;
170 ret = LOS_TaskCreate(&thread_id2, &task3);
171 if (ret != LOS_OK)
172 {
173 printf("Failed to create sem_two_thread ret:0x%x\n", ret);
174 return;
175 }
176}
177```
178
179control_thread函数中通过LOS_SemPost函数释放信号量,sem_one_thread和sem_two_thread函数中,则阻塞等待sem信号量。当Thread_Control函数中释放两次信号量,sem_one_thread和sem_two_thread同步运行;当control_thread函数只释放一次信号量,sem_one_thread和sem_two_thread轮流执行。
180
181```c
182void control_thread()
183{
184 unsigned int count = 0;
185
186 while (1)
187 {
188 /*释放两次信号量,sem_one_thread和sem_two_thread同步执行;
189 释放一次信号量,sem_one_thread和sem_two_thread交替执行*/
190 if (count++%3)
191 {
192 LOS_SemPost(m_sem);
193 printf("control_thread Release once Semaphore\n");
194 }
195 else
196 {
197 LOS_SemPost(m_sem);
198 LOS_SemPost(m_sem);
199 printf("control_thread Release twice Semaphore\n");
200 }
201
202 LOS_Msleep(1000);
203 }
204}
205
206void sem_one_thread()
207{
208 while (1)
209 {
210 /*申请信号量*/
211 LOS_SemPend(m_sem, LOS_WAIT_FOREVER);
212
213 printf("sem_one_thread get Semaphore\n");
214 LOS_Msleep(100);
215 }
216}
217
218void sem_two_thread()
219{
220 while (1)
221 {
222 /*申请信号量*/
223 LOS_SemPend(m_sem, LOS_WAIT_FOREVER);
224
225 printf("sem_two_thread get Semaphore\n");
226 LOS_Msleep(100);
227 }
228}
229```
230
231## 编译调试
232
233### 修改 BUILD.gn 文件
234
235修改 `vendor/lockzhiner/lingpi/sample` 路径下 BUILD.gn 文件,指定 `a2_kernel_semaphore` 参与编译。
236
237```r
238"a2_kernel_semaphore",
239```
240
241在主目录下输入编译命令。
242
243```shell
244hb build -f
245```
246
247### 运行结果
248
249例程代码编译烧写到开发板后,按下开发板的RESET按键,通过串口软件查看日志,control_thread一次释放两个信号量,sem_one_thread和sem_two_thread同步执行;control_thread一次释放一个信号量,sem_one_thread和sem_two_thread交替执行。
250
251```r
252control_thread Release once Semaphore
253sem_one_thread get Semaphore
254control_thread Release once Semaphore
255sem_two_thread get Semaphore
256control_thread Release twice Semaphore
257sem_two_thread get Semaphore
258sem_one_thread get Semaphore
259```
260