环形缓冲区

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
posted @ 2018-12-11 11:02  thomas_blog  阅读(153)  评论(0编辑  收藏  举报