• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 小凌派-RK2206开发板OpenHarmonyOS内核开发-信号量
2
3## 实验内容
4
5本例程演示如何在小凌派-RK2206开发板上使用鸿蒙LiteOS-M内核接口,通过信号量控制不同的线程,实现任务之间的同步。
6
7![小凌派-RK2206开发板](../../docs/figures/lockzhiner-rk2206.jpg)
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