环形缓冲区
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