目录
本学笔记基于zephyr 工程版本 2.2.99,主机环境为ubuntu18.04,开发平台 nrf52840dk_nrf52840
摘要
PIPE(管道)是一个内核对象,可以用于发送数据流到另一个线程。管道用于同步或者异步传输一整块数据,或者一部分数据。
1 概念
管道可以被配置使用一个ring buffer,去存储那些已经被发送,但是没有被接收的数据。也可以不是使用ring buffer。
任意数量的管道可以被定义。引用管道时,使用的是管道的地址。
管道的关键属性:
size:表示管道的ring buffer的大小。如果这值是0,那么代表不使用 ring buffer。
管道使用之前必须被初始化。初始化后管道被设置成空。
2 实现
2.1 定义一个PIPE
可以使用struct k_pipe类型定义一个管道变量,定义一个可选的unsigned char 类型的buffer。它必须使用k_pipe_init()去初始化。
下面示例代码,定义并初始化一个包含100字节(4字节对齐)buffer的管道。
unsigned char __aligned(4) my_ring_buffer[100];
struct k_pipe my_pipe;
k_pipe_init(&my_pipe, my_ring_buffer, sizeof(my_ring_buffer));
或者,在编译时使用K_PIPE_DEFINE宏去定义和初始化一个PIPE。
下面代码与上面的功能相同:
K_PIPE_DEFINE(my_pipe, 100, 4);
2.2 写数据到PIPE
可以使用k_pipe_put()写数据到管道。
下面的示例代码,使用一个管道传输数据,数据从一个"生产"线程到一个或多个“消费”线程。如果由于消费线程没有及时读取数据,那个这个管道会被填满。生产线程将等待一段时间。
struct message_header {
...
};
void producer_thread(void)
{
unsigned char *data;
size_t total_size;
size_t bytes_written;
int rc;
...
while (1) {
/* Craft message to send in the pipe */
data = ...;
total_size = ...;
/* send data to the consumers */
rc = k_pipe_put(&my_pipe, data, total_size, &bytes_written,
sizeof(struct message_header), K_NO_WAIT);
if (rc < 0) {
/* Incomplete message header sent */
...
} else if (bytes_written < total_size) {
/* Some of the data was sent */
...
} else {
/* All data sent */
...
}
}
}
2.3 从PIPE读数据
可以使用k_pipe_get()读取管道数据。
下面的示例使用管道处理“生产”线程的数据:
void consumer_thread(void)
{
unsigned char buffer[120];
size_t bytes_read;
struct message_header *header = (struct message_header *)buffer;
while (1) {
rc = k_pipe_get(&my_pipe, buffer, sizeof(buffer), &bytes_read,
sizeof(header), K_MSEC(100));
if ((rc < 0) || (bytes_read < sizeof (header))) {
/* Incomplete message header received */
...
} else if (header->num_data_bytes + sizeof(header) > bytes_read) {
/* Only some data was received */
...
} else {
/* All data was received */
...
}
}
}
3 参考链接
https://docs.zephyrproject.org/latest/reference/kernel/data_passing/pipes.html