环形缓冲区
Linux内核文件kfifo.h和kfifo.c
举例
#include <sys/mman.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#define report_exceptional_condition() abort ()
struct ring_buffer
{
void *address;
unsigned long count_bytes;
unsigned long write_offset_bytes;
unsigned long read_offset_bytes;
};
// Warning order should be at least 12 for Linux
void ring_buffer_create(struct ring_buffer *buffer, unsigned long order)
{
char path[] = "/dev/shm/ring-buffer-XXXXXX";
int file_descriptor;
void *address;
int status;
file_descriptor = mkstemp(path);
if(file_descriptor < 0)
{
report_exceptional_condition();
}
status = unlink(path);
if(status)
{
report_exceptional_condition();
}
buffer->count_bytes = 1UL << order;
buffer->write_offset_bytes = 0;
buffer->read_offset_bytes = 0;
status = ftruncate(file_descriptor, buffer->count_bytes);
if(status)
{
report_exceptional_condition();
}
buffer->address = mmap(NULL, buffer->count_bytes << 1, PROT_NONE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if(buffer->address == MAP_FAILED)
{
report_exceptional_condition();
}
address = mmap(buffer->address, buffer->count_bytes, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_SHARED, file_descriptor, 0);
if(address != buffer->address)
{
report_exceptional_condition();
}
address = mmap(buffer->address + buffer->count_bytes,
buffer->count_bytes, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_SHARED, file_descriptor, 0);
if(address != buffer->address + buffer->count_bytes)
{
report_exceptional_condition();
}
status = close(file_descriptor);
if(status)
{
report_exceptional_condition();
}
}
void ring_buffer_free(struct ring_buffer *buffer)
{
int status;
status = munmap(buffer->address, buffer->count_bytes << 1);
if(status)
{
report_exceptional_condition();
}
}
void *ring_buffer_write_address(struct ring_buffer *buffer)
{
// void pointer arithmetic is a constraint violation.
return buffer->address + buffer->write_offset_bytes;
}
void ring_buffer_write_advance(struct ring_buffer *buffer, unsigned long count_bytes)
{
buffer->write_offset_bytes += count_bytes;
}
void *ring_buffer_read_address(struct ring_buffer *buffer)
{
return buffer->address + buffer->read_offset_bytes;
}
void ring_buffer_read_advance(struct ring_buffer *buffer, unsigned long count_bytes)
{
buffer->read_offset_bytes += count_bytes;
if(buffer->read_offset_bytes >= buffer->count_bytes)
{
//如果读指针大于等于缓冲区长度,那些读写指针同时折返回[0, buffer_size]范围内
buffer->read_offset_bytes -= buffer->count_bytes;
buffer->write_offset_bytes -= buffer->count_bytes;
}
}
unsigned long ring_buffer_count_bytes(struct ring_buffer *buffer)
{
return buffer->write_offset_bytes - buffer->read_offset_bytes;
}
unsigned long ring_buffer_count_free_bytes(struct ring_buffer *buffer)
{
return buffer->count_bytes - ring_buffer_count_bytes(buffer);
}
void ring_buffer_clear(struct ring_buffer *buffer)
{
buffer->write_offset_bytes = 0;
buffer->read_offset_bytes = 0;
}
void print(struct ring_buffer *buffer)
{
printf("ring_buffer_count_bytes %lu\n", ring_buffer_count_bytes(buffer));
printf("ring_buffer_count_free_bytes %lu\n", ring_buffer_count_free_bytes(buffer));
printf("ring_buffer_read_address %p\n", ring_buffer_read_address(buffer));
printf("ring_buffer_write_address %p\n", ring_buffer_write_address(buffer));
}
int main()
{
struct ring_buffer buffer = {0};
ring_buffer_create(&buffer, 16);
print(&buffer);
ring_buffer_write_advance(&buffer, 1140);
print(&buffer);
ring_buffer_read_advance(&buffer, 450);
print(&buffer);
ring_buffer_clear(&buffer);
print(&buffer);
ring_buffer_free(&buffer);
return 0;
}
实验效果
ring_buffer_count_bytes 0
ring_buffer_count_free_bytes 65536
ring_buffer_read_address 0x7fa76d30a000
ring_buffer_write_address 0x7fa76d30a000
ring_buffer_count_bytes 1140
ring_buffer_count_free_bytes 64396
ring_buffer_read_address 0x7fa76d30a000
ring_buffer_write_address 0x7fa76d30a474
ring_buffer_count_bytes 690
ring_buffer_count_free_bytes 64846
ring_buffer_read_address 0x7fa76d30a1c2
ring_buffer_write_address 0x7fa76d30a474
ring_buffer_count_bytes 0
ring_buffer_count_free_bytes 65536
ring_buffer_read_address 0x7fa76d30a000
ring_buffer_write_address 0x7fa76d30a000
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!