管道:字节流与新版 API

本页依据 文档基线与后续更新 中记录的 Zephyr main 快照更新。

管道传递字节流,不保存消息边界。它可使用环形缓冲区,也可在缓冲区大小为 0 时由 发送者和接收者直接配合传输。应用需要自己定义帧长度、编码、结束条件和错误恢复。

新版接口与旧教程差异

当前公共 API 使用下面的四参数读写接口:

int k_pipe_write(struct k_pipe *pipe, const uint8_t *data,
                 size_t len, k_timeout_t timeout);
int k_pipe_read(struct k_pipe *pipe, uint8_t *data,
                size_t len, k_timeout_t timeout);

返回非负值表示实际传输的字节数,负值表示错误。原教程中的 k_pipe_put/get、bytes_written/bytes_read 输出参数和 min_xfer 语义 不适用于这一接口,不能只替换函数名。

定义与最小示例

下面是单线程使用有缓冲管道的完整示例,先写入 4 字节再读出;环形缓冲区足以容纳全部数据。

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>

K_PIPE_DEFINE(byte_stream, 64, 4);

int main(void)
{
    const uint8_t tx[] = { 1, 2, 3, 4 };
    uint8_t rx[sizeof(tx)];
    int written = k_pipe_write(&byte_stream, tx, sizeof(tx), K_NO_WAIT);

    if (written != sizeof(tx)) {
        printk("write result: %d\n", written);
        return 0;
    }
    int received = k_pipe_read(&byte_stream, rx, sizeof(rx), K_NO_WAIT);
    printk("read result: %d\n", received);
    return 0;
}

运行时初始化使用 k_pipe_init()。不需要内部缓冲区时传入 NULL, 0, 此时应由不同线程完成双方通信,不能期待同一线程先完成阻塞写入后再去读取。

部分传输

一次调用可能只完成部分请求,必须按返回的长度移动指针。 下面的辅助函数用于线程之间已经启动接收者的场景,它返回已写长度并保留错误:

static int send_bytes(struct k_pipe *pipe, const uint8_t *data,
                      size_t size, size_t *done)
{
    *done = 0;
    while (*done < size) {
        int rc = k_pipe_write(pipe, data + *done, size - *done,
                              K_MSEC(100));
        if (rc < 0) {
            return rc;
        }
        if (rc == 0) {
            return -EAGAIN;
        }
        *done += (size_t)rc;
    }
    return 0;
}

此片段需要 <errno.h>。每轮的 100 ms 不是整个消息的总期限; 若业务要求总超时,应计算剩余时间。重试时从 done 偏移继续,避免重复发送已写入的前缀。 读取同样按实际长度累计,并在读取消息正文前验证长度字段,避免越过接收缓冲区。

错误、重置与关闭

  • -EAGAIN:在期限内没有传输任何数据。

  • -ECANCELED:操作被 k_pipe_reset() 中断,或管道正在重置。

  • -EPIPE:管道已经关闭。

k_pipe_reset() 丢弃未读数据、唤醒等待者,并让管道恢复可用的打开状态。 k_pipe_close() 关闭管道并结束等待。多线程应用应统一决定何时重置或关闭, 并让双方重建消息边界;重置后的字节流不能当作旧消息的连续后半段。

当前示例按公共头文件的函数声明编写。官方说明页的个别示意片段可能仍残留旧参数, 集成时应同时核对所用提交的 include/zephyr/kernel.h。

上游依据