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