README_zh.md
1# 小凌派-RK2206开发板OpenHarmonyOS内核开发-队列
2
3## 实验内容
4
5本例程演示如何在小凌派-RK2206开发板上使用鸿蒙LiteOS-M内核接口,进行队列编程开发。例程创建一个队列,两个任务;任务1调用写队列接口发送消息,任务2调用读队列接口接收消息。
6
7
8
9## 程序设计
10
11队列,是一种常用于任务间通信的数据结构。队列可以在任务与任务、任务与中断之间传递消息,实现任务接收来自其他任务或者中断的不固定长度的消息。任务能够从队列里面读取消息,当队列中的消息为空时,读取消息的任务将被阻塞,阻塞的时间可以由用户自行定义,任务会一直等待队列里新消息的到来或者直到等待的时间超过阻塞时间,任务就会从阻塞态转为就绪态。
12
13队列中可以存储有限的、大小固定的数据结构。任务与任务、任务与中断之间要传递的数据保存在队列中;队列所能保存的最大数据数量叫做队列的长度,创建队列的时候需要指定数据的大小和队列的长度。
14
15通过队列,任务或中断可以将一条或者多条消息放入队列中,这样其他的任务就可以通过队列获取消息。当多个消息发送到队列时,通常是将先进队列的消息先传出去,即队列支持先进先出的原则(FIFO)。
16
17### API分析
18
19#### LOS_QueueCreate()
20
21```c
22UINT32 LOS_QueueCreate(CHAR *queueName,
23 UINT16 len,
24 UINT32 *queueID,
25 UINT32 flags,
26 UINT16 maxMsgSize);
27```
28
29**描述:**
30
31创建一个队列,由系统动态申请队列空间。
32
33**参数:**
34
35| 名字 | 描述 |
36| :--------- | :----------------- |
37| queueName | 需要创建的队列名 |
38| len | 需要创建队列的长度 |
39| queueID | 创建生成的队列ID |
40| flags | 队列模式 |
41| maxMsgSize | 队列节点大小 |
42
43**返回值:**
44
45| 返回值 | 描述 |
46| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--- |
47| LOS_OK | 成功 |
48| LOS_ERRNO_QUEUE_CB_UNAVAILABLE`<br>` LOS_ERRNO_QUEUE_CREATE_NO_MEMORY `<br>` LOS_ERRNO_QUEUE_CREAT_PTR_NULL `<br>` LOS_ERRNO_QUEUE_PARA_ISZERO `<br>` LOS_ERRNO_QUEUE_SIZE_TOO_BIG | 失败 |
49
50#### LOS_QueueDelete()
51
52```c
53UINT32 LOS_QueueDelete(UINT32 queueID);
54```
55
56**描述:**
57
58根据队列ID删除一个指定队列。
59
60**参数:**
61
62| 名字 | 描述 |
63| :------ | :--------------- |
64| queueID | 需要删除的队列ID |
65
66**返回值:**
67
68| 返回值 | 描述 |
69| :------------------------------------------------------------------------------------------- | :--- |
70| LOS_OK | 成功 |
71| LOS_ERRNO_QUEUE_PTR_NULL`<br>` LOS_ERRNO_QUEUE_INVALID `<br>` LOS_ERRNO_QUEUE_NOT_CREATE | 失败 |
72
73#### LOS_QueueRead()
74
75```c
76UINT32 LOS_QueueRead(UINT32 queueID,
77 VOID *bufferAddr,
78 UINT32 bufferSize,
79 UINT32 timeOut);
80```
81
82**描述:**
83
84读取指定队列头节点中的数据(队列节点中的数据实际上是一个地址)。
85
86**参数:**
87
88| 名字 | 描述 |
89| :--------- | :--------------- |
90| queueID | 需要读取的队列ID |
91| bufferAddr | 缓冲区指针 |
92| bufferSize | 缓冲区大小 |
93| timeout | 超时时间 |
94
95**返回值:**
96
97| 返回值 | 描述 |
98| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--- |
99| LOS_OK | 成功 |
100| LOS_ERRNO_QUEUE_INVALID`<br>` LOS_ERRNO_QUEUE_READ_PTR_NULL `<br>` LOS_ERRNO_QUEUE_READSIZE_ISZERO `<br>` LOS_ERRNO_QUEUE_READ_IN_INTERRUPT `<br>` LOS_ERRNO_QUEUE_NOT_CREATE `<br>` LOS_ERRNO_QUEUE_ISEMPTY `<br>` LOS_ERRNO_QUEUE_PEND_IN_LOCK `<br>` LOS_ERRNO_QUEUE_TIMEOUT | 失败 |
101
102### 软件设计
103
104**主要代码分析**
105
106在queue_example函数中,通过LOS_QueueCreate函数创建一个队列;通过LOS_TaskCreate函数创建两个线程:msg_write_thread和msg_read_thread。
107
108```c
109void queue_example()
110{
111 unsigned int thread_id1;
112 unsigned int thread_id2;
113 TSK_INIT_PARAM_S task1 = {0};
114 TSK_INIT_PARAM_S task2 = {0};
115 unsigned int ret = LOS_OK;
116
117 ret = LOS_QueueCreate("queue", MSG_QUEUE_LENGTH, &m_msg_queue, 0, BUFFER_LEN);
118 if (ret != LOS_OK)
119 {
120 printf("Failed to create Message Queue ret:0x%x\n", ret);
121 return;
122 }
123
124 task1.pfnTaskEntry = (TSK_ENTRY_FUNC)msg_write_thread;
125 task1.uwStackSize = 2048;
126 task1.pcName = "msg_write_thread";
127 task1.usTaskPrio = 24;
128 ret = LOS_TaskCreate(&thread_id1, &task1);
129 if (ret != LOS_OK)
130 {
131 printf("Failed to create msg_write_thread ret:0x%x\n", ret);
132 return;
133 }
134
135 task2.pfnTaskEntry = (TSK_ENTRY_FUNC)msg_read_thread;
136 task2.uwStackSize = 2048;
137 task2.pcName = "msg_read_thread";
138 task2.usTaskPrio = 25;
139 ret = LOS_TaskCreate(&thread_id2, &task2);
140 if (ret != LOS_OK)
141 {
142 printf("Failed to create msg_read_thread ret:0x%x\n", ret);
143 return;
144 }
145}
146```
147
148msg_write_thread函数每隔1s,通过LOS_QueueWrite函数向队列中发送消息。
149
150```c
151void msg_write_thread(void)
152{
153 unsigned int data = 0;
154 unsigned int ret = LOS_OK;
155
156 while (1)
157 {
158 data++;
159 ret = LOS_QueueWrite(m_msg_queue, (void *)&data, sizeof(data), LOS_WAIT_FOREVER);
160 if (LOS_OK != ret)
161 {
162 printf("%s write Message Queue msg fail ret:0x%x\n", __func__, ret);
163 }
164 else
165 {
166 printf("%s write Message Queue msg:%u\n", __func__, data);
167 }
168
169 /*delay 1s*/
170 LOS_Msleep(1000);
171 }
172}
173```
174
175msg_read_thread函数通过LOS_QueueRead函数读取队列中的消息,当队列中没有消息的时候,msg_read_thread函数阻塞等待消息。
176
177```c
178void msg_read_thread(void)
179{
180 unsigned int addr;
181 unsigned int ret = LOS_OK;
182 unsigned int *pData = NULL;
183
184 while (1)
185 {
186 /*wait for message*/
187 ret = LOS_QueueRead(m_msg_queue, (void *)&addr, BUFFER_LEN, LOS_WAIT_FOREVER);
188 if (ret == LOS_OK)
189 {
190 pData = addr;
191 printf("%s read Message Queue msg:%u\n", __func__, *pData);
192 }
193 else
194 {
195 printf("%s read Message Queue fail ret:0x%x\n", __func__, ret);
196 }
197 }
198}
199```
200
201## 编译调试
202
203### 修改 BUILD.gn 文件
204
205修改 `vendor/lockzhiner/lingpi/sample` 路径下 BUILD.gn 文件,指定 `a5_kernel_queue` 参与编译。
206
207```r
208"a5_kernel_queue",
209```
210
211在主目录下输入编译命令。
212
213```shell
214hb build -f
215```
216
217### 运行结果
218
219例程代码编译烧写到开发板后,按下开发板的RESET按键,通过串口软件查看日志,Thread_Msg_Write函数1S写入一次数据,此时Thread_Msg_Read函数退出阻塞读取数据并打印接收的数据。
220
221```r
222msg_write_thread write Message Queue msg:1
223msg_read_thread read Message Queue msg:1
224msg_write_thread write Message Queue msg:2
225msg_read_thread read Message Queue msg:2
226msg_write_thread write Message Queue msg:3
227msg_read_thread read Message Queue msg:3
228msg_write_thread write Message Queue msg:4
229msg_read_thread read Message Queue msg:4
230```
231