SPSC_PBUF ( Single Producer Single Consumer Packet Buffer ) 单生产者单消费者包缓冲器是一个循环缓冲区,SPSC_PBUF 中的数据以包为单位进行管理,并且包的大小不定,用户以包为单位从 SPSC_PBUF 中读取或者存储。为了减少数据在内存中的复制,生产数据分为两个步骤:分配数据包空间和填充数据并提交。消费数据包也分两个步骤:消费者请求数据包,使用数据并释放数据包。与 MPSC 不同的是 SPSC_PBUF 只支持一个生产者和一个消费者,其实现的重点是高性能和低内存占用:

  • 管理结构简单,占用内存小
  • 使用无锁、无竞争的设计
  • cache 一致性管理 ( 针对多核 )

配置 链接到标题

当配置 CONFIG_SPSC_PBUF=y 后允许使用 SPSC。默认情况下会开启 CONFIG_SPSC_PBUF_CACHE_FLAG=y 进行 cache 一致性的处理。当配置 CONFIG_SPSC_PBUF_CACHE_ALWAYS=y 强制进行 cache 一致性处理, 当配置 CONFIG_SPSC_PBUF_CACHE_NEVER=y 强制不进行 cache 一致性处理。通过 CONFIG_SPSC_PBUF_REMOTE_DCACHE_LINE 可以配置 SPSC 对应的 cache line 大小,默认是 32 字节。 当 SPSC_PBUF 管理的 buffer 处理 nocache 区时,建议开启 CONFIG_SPSC_PBUF_CACHE_NEVER=y。 当 SPSC_PBUF 管理的 buffer 处理 cache 区,且是多核访问,建议开启 CONFIG_SPSC_PBUF_CACHE_ALWAYS=y。 当配置了 CONFIG_SPSC_PBUF_UTILIZATION=y 的情况下 SPSC_PBUF 会跟踪 buf 的使用情况。

使用方法 链接到标题

SPSC 的 API 详细使用方法参考: zephyr/include/zephyr/sys/spsc_pbuf.h SPSC 使用方法类似于 MPSC:

  • 初始化 spsc_pbuf_init
  • 从 SPSC 申请空间 spsc_pbuf_alloc
  • 填充数据包
  • 提交数据包 spsc_pbuf_commit
  • 从 SPSC 中请求一个数据包 spsc_pbuf_claim
  • 处理数据
  • 通知 SPSC 释放数据包 spsc_pbuf_free

与 MPSC 不同的是,SPSC 不用定义包结构,包在 SPSC 内部进行管理, SPSC 不需要专门的管理结构空间,管理结构放在 SPSC 管理的 buf 中。使用示例如下

static uint8_t spsc_buf [200] __aligned ( MAX ( Z_SPSC_PBUF_DCACHE_LINE, 4 )) ;
struct spsc_pbuf *spsc;
char *buf, *rbuf;
int rv;
uint16_t len = 0;

spsc = spsc_pbuf_init ( spsc_buf, sizeof ( spsc_buf ) , SPSC_PBUF_CACHE ) ;

rv = spsc_pbuf_alloc ( spsc, 30, &buf ) ;
if ( rv >= 30 ) {
    memset ( buf, 0x5a, 30 ) ;
    spsc_pbuf_commit ( spsc, rv ) ;
}

len = spsc_pbuf_claim ( spsc, &rbuf ) ;
if ( rbuf ) {
    hex_dump ( rbuf, len ) ;
    spec_pbuf_free ( spsc, rbuf ) ;
}

注意:spsc 的包内存长度被限制在 65280 字节#define SPSC_PBUF_MAX_LEN 0xFF00

其它 API 链接到标题

除了前面 4 个 API 外,SPSC 还提供其它的辅助 API 下面 2 个 API 是简化生产者和消费的操作,不必分两步进行,但会多一次内存拷贝

//向 pb 中写入长度为 len 的包,内容为 buf
int spsc_pbuf_write ( struct spsc_pbuf *pb, const char *buf, uint16_t len ) ;

//从 pb 中读出一个包的数据到 buf,如果包长度大于 len,返回-ENOMEM
int spsc_pbuf_read ( struct spsc_pbuf *pb, char *buf, uint16_t len ) ;

下面 2 个 API 时获取 SPSC 的状态:

//获取 pb 的容量
static inline uint32_t spsc_pbuf_capacity ( struct spsc_pbuf *pb ) ;

//获取 pb 最大的使用量情况, 只在 CONFIG_SPSC_PBUF_UTILIZATION=y 有效,否则返回-ENOTSUP
int spsc_pbuf_get_utilization ( struct spsc_pbuf *pb ) ;

参考 链接到标题

https://docs.zephyrproject.org/3.5.0/kernel/data_structures/spsc_pbuf.html