• 多线程环形缓冲区


    #ifndef __BUFFER_H__
    #define __BUFFER_H__
    
    #include <stdint.h>
    /*
     * http://en.wikipedia.org/wiki/Circular_buffer : Mirroring
     *
     * The capacity of circle buffer must be a power of two !
     *
     * The source and sink of data can implement independent policies for dealing
     * with a full buffer and overrun while adhering to the rule that
     *
     * only the source of data modifies the write index and
     * only the sink of data modifies the read index.
     *
     * This can result in elegant and robust circular buffer implementations
     * even in multi-threaded environments.
     *
     * |<------- CAPACITY ------------>|<---- Writable + Readable ---->|
     * |         MSB = 0               |         MSB = 1               |
     * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
     * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     *         ^                               ^
     *         R ---- R^W == CAPACITY -------- W ---- FULL  : R.MSB != W.MSB
     *         W ---- R^W == 0 ---------------------- EMPTY : R.MSB == W.MSB
     *
     *         W >= R : W - R = Readable
     *         W <  R : R - W = Writable
     *
     *         Emyty : W ^ R == 0        : Readable == 0
     *         Full  : W ^ R == CAPACITY : Writable == 0
     */
    
    typedef struct
    {
      uint32_t write_index;
      uint32_t read_index;
      uint32_t capacity;
      uint8_t * data;
    } buffer_t;
    
    buffer_t *buffer_create( uint32_t capacity );
    
    void buffer_delete( buffer_t *buffer );
    
    void buffer_init( buffer_t *buffer, uint8_t * data,
      uint32_t capacity );
    
    void buffer_clear( buffer_t *buffer );
    
    uint32_t buffer_readable( buffer_t *buffer );
    
    uint32_t buffer_writable( buffer_t *buffer );
    
    uint32_t buffer_full( buffer_t *buffer );
    
    uint32_t buffer_empty( buffer_t *buffer );
    
    void buffer_flush( buffer_t *buffer, uint32_t bytes );
    
    void buffer_read( buffer_t *buffer, uint8_t *data,
      uint32_t length );
    
    void buffer_write( buffer_t *buffer,
      const uint8_t *data, uint32_t length );
    
    uint32_t buffer_write_ex( buffer_t *buffer,
      const uint8_t *data, uint32_t length );
    
    uint32_t buffer_read_ex( buffer_t *buffer,
      uint8_t *data, uint32_t length );
    
    
    #endif /* __BUFFER_H__ */
    #include "buffer.h"
    
    #include <stdlib.h>
    #include <string.h>
    
    void buffer_delete( buffer_t *buffer )
    {
      free( buffer );
    }
    
    // capacity = 2^n :: struct : buffer[ capacity ]
    buffer_t *buffer_create( uint32_t capacity )
    {
      void * p = malloc( sizeof(buffer_t) + capacity );
      buffer_t *buffer = (buffer_t *) p;
      if ( buffer == NULL )
        return NULL;
    
      buffer->capacity = capacity;
      buffer_clear( buffer );
    
      return buffer;
      // buffer_init( buffer, ( (uint8_t *)buffer ) + sizeof(buffer_t), capacity )
    }
    
    // capacity = 2^n
    void buffer_init( buffer_t *buffer, uint8_t * data,
      uint32_t capacity )
    {
      buffer->data = data;
      buffer->capacity = capacity;
      buffer_clear( buffer );
    }
    
    void buffer_clear( buffer_t *buffer )
    {
      buffer->read_index = buffer->write_index = 0;
    }
    
    uint32_t buffer_empty( buffer_t *buffer )
    {
      return buffer->read_index == buffer->write_index;
    }
    
    uint32_t buffer_full( buffer_t *buffer )
    {
      return buffer->capacity == ( buffer->read_index ^ buffer->write_index );
    }
    
    uint32_t buffer_readable( buffer_t *buffer )
    {
      if ( buffer->write_index >= buffer->read_index )
        return buffer->write_index - buffer->read_index;
      else
        return buffer->capacity + buffer->write_index - buffer->read_index;
    }
    
    uint32_t buffer_writable( buffer_t *buffer )
    {
      if ( buffer->write_index >= buffer->read_index )
        return buffer->capacity - ( buffer->write_index - buffer->read_index );
      else
        return buffer->read_index - buffer->write_index;
    }
    
    void buffer_flush( buffer_t *buffer, uint32_t bytes )
    {
      // we can't flush more bytes than there are
      uint32_t flushable = buffer_readable( buffer );
    
      if ( bytes > flushable )
        bytes = flushable;
    
      buffer->read_index = ( buffer->read_index + bytes )
        & ( 2 * buffer->capacity - 1 );
    }
    
    void buffer_read( buffer_t *buffer, uint8_t *data, uint32_t length )
    {
      // clear MSB
      uint32_t read_index = buffer->read_index & ( buffer->capacity - 1 );
    
      if ( read_index + length <= buffer->capacity )
        memcpy( data, buffer->data + read_index, length );
      else
      {
        uint32_t upper = buffer->capacity - read_index;
        uint32_t lower = length - upper;
        memcpy( data, buffer->data + read_index, upper );
        memcpy( data + upper, buffer->data, lower );
      }
    
      buffer->read_index = ( buffer->read_index + length )
        & ( 2 * buffer->capacity - 1 );
    }
    
    void buffer_write( buffer_t *buffer, const uint8_t *data,
      uint32_t length )
    {
      // clear MSB
      uint32_t write_index = buffer->write_index & ( buffer->capacity - 1 );
    
      if ( write_index + length <= buffer->capacity )
        memcpy( buffer->data + write_index, data, length );
      else
      {
        uint32_t upper = buffer->capacity - write_index;
        uint32_t lower = length - upper;
        memcpy( buffer->data + write_index, data, upper );
        memcpy( buffer->data, data + upper, lower );
      }
    
      buffer->write_index = ( buffer->write_index + length )
        & ( 2 * buffer->capacity - 1 );
    }
    
    uint32_t buffer_read_ex( buffer_t *buffer, uint8_t *data,
      uint32_t length )
    {
      uint32_t readable = buffer_readable( buffer );
    
      if ( length > readable )
        length = readable;
    
      if ( length > 0 )
        buffer_read( buffer, data, length );
    
      return length;
    }
    
    uint32_t buffer_write_ex( buffer_t *buffer, const uint8_t *data,
      uint32_t length )
    {
      uint32_t writable = buffer_writable( buffer );
    
      if ( length > writable )
        length = writable;
    
      if ( length > 0 )
        buffer_write( buffer, data, length );
    
      return length;
    }

    循环缓冲实现(ringbuffer/circularbuffer)

    http://www.haogongju.net/art/2689660

    /****************************************************************************************************
    * buf : 存放数据的缓冲区地址
    * size: 缓冲区的大小(必须是2的幂)
    * in :写指针下标
    * out :读指针下标
    * 缓冲区模型如下:size固定大小,in的值始终大于等于out的值
    * 先从ringbuf->in到缓冲区末端写数据,如果还没写完,再从缓冲区头开始写入剩下的,从而实现了循环缓冲。
    * +--------------+(in)-----------------+(size)
    * +-----+(out)-------------------------+
    * 那么可用的缓冲空间大小就是(size - in + out)
    * * 所以写数据时 * 1.先从length和(ringbuf->size - ringbuf->in + ringbuf->out)之间取一个较小的值赋给length * 2.再判断缓冲区的末端(buffer->size - (buffer->in & (buffer->size - 1)))大小是否够保存length的数据给len * 3.拷贝len长度的数据到缓冲区的末端 memcpy(buffer->buf + (buffer->in & (buffer->size - 1)), data, len); * 4.再拷贝剩下的数据到缓冲区的前端 memcpy(buffer->buf, data + len, length - len); 如果length - len为0则无操作。 * 5.写指针的下标增加length长度。 * 6.返回实际写入缓冲区的长度。 * * 读取数据:
    * * 1.数据量的大小由(buffer->in - buffer->out)决定 * amount和(buffer->in - buffer->out)取小值给amount,作为一次读取的数据大小 * 2.尾部缓冲数据大小由(buffer->size - (buffer->out & (buffer->size - 1)))决定 * 判断尾部数据和总需求数据大小,取小值给len * 3.先拷贝尾部缓冲的数据到目的memcpy(target, buffer->buf + (buffer->out & (buffer->size - 1)), len); * 4.再拷贝头部缓冲数据 memcpy(target + len, buffer->buf, amount - len); amount - len为0则无操作。 * 5.读指针的下标增加amount大小 * 6.返回实际读取的数据大小。
    * * 注意: * 当(ringbuf->in == ringbuf->out + ringbuf->size)时,表示缓冲区已满. * 此时得到的较小值一定是0,后面实际写入的字节数也全为0。 * * 既然ringbuf->size是2的幂,那么(ringbuf->size-1)也就是一个除最高位为0,其余二进制位都为1的一个数值 * 也就能保证(ringbuf->in & (ringbuf->size - 1))不会超过(ringbuf->size - 1),和(ringbuf->in)%(ringbuf->size - 1)的效果一样 * 从上面可以看出,ringbuf->in的值可以从0变化到超过fifo->size的数值
    * * ringbuf->out也如此,但它们的差不会超过ringbuf->size。 ***************************************************************************************************
    */ typedef struct cycle_buffer { unsigned char* buf; unsigned int size; unsigned int in; unsigned int out; } RingBuffer; RingBuffer *RingBuffer_create( int length ); void RingBuffer_destroy( RingBuffer *buffer ); int RingBuffer_read( RingBuffer *buffer, char *target, int amount ); int RingBuffer_write( RingBuffer *buffer, char *data, int length ); int RingBuffer_empty( RingBuffer *buffer ); int RingBuffer_Reset( RingBuffer *buffer ); #define min(x, y) ((x) < (y) ? (x) : (y)) #define ROUND_UP_2(num) (((num)+1)&~1) #define DEFAULT_BUF_SIZE (2*1024*1024) RingBuffer *RingBuffer_create( int length ) { unsigned int size = ROUND_UP_2( length ); if ( ( size & ( size - 1 ) ) || ( size < DEFAULT_BUF_SIZE ) ) { size = DEFAULT_BUF_SIZE; }
    RingBuffer
    *buffer = (RingBuffer *) malloc( sizeof(RingBuffer) ); if ( !buffer ) { return NULL; }
    memset( buffer,
    0, sizeof(RingBuffer) ); buffer->size = size; buffer->in = 0; buffer->out = 0; buffer->buf = (unsigned char *) malloc( size ); if ( !buffer->buf ) { free( buffer ); return NULL; }
    memset( buffer
    ->buf, 0, size ); return buffer; }
    void RingBuffer_destroy( RingBuffer *buffer ) { if ( buffer ) { free( buffer->buf ); free( buffer ); } } int RingBuffer_Reset( RingBuffer *buffer ) { if ( buffer == NULL ) { return -1; } buffer->in = 0; buffer->out = 0; memset( buffer->buf, 0, buffer->size ); return 0; } int RingBuffer_empty( RingBuffer *buffer ) { return buffer->in == buffer->out; } int RingBuffer_write( RingBuffer *buffer, char *data, int length ) { unsigned int len = 0; length = min( length, buffer->size - buffer->in + buffer->out ); len = min( length, buffer->size - ( buffer->in & ( buffer->size - 1 ) ) ); memcpy( buffer->buf + ( buffer->in & ( buffer->size - 1 ) ), data, len ); memcpy( buffer->buf, data + len, length - len ); buffer->in += length; return length; } int RingBuffer_read( RingBuffer *buffer, char *target, int amount ) { unsigned int len = 0; amount = min( amount, buffer->in - buffer->out ); len = min( amount, buffer->size - ( buffer->out & ( buffer->size - 1 ) ) ); memcpy( target, buffer->buf + ( buffer->out & ( buffer->size - 1 ) ), len ); memcpy( target + len, buffer->buf, amount - len ); buffer->out += amount; return amount; }

  • 相关阅读:
    程序员如何判断是否到了该辞职的时候?
    牛客网
    C++继承详解:共有(public)继承,私有(private)继承,保护(protected)继承
    为什么构造函数不能声明为虚函数,析构函数可以
    为什么要线程同步,说出线程同步的几种方法
    内存字节对齐
    std::map的删除
    阻塞调用ShellExecute函数
    无法打开包括文件:“SDKDDKVer.h”: No such file or directory
    Legacy C++ MongoDB Driver
  • 原文地址:https://www.cnblogs.com/shangdawei/p/3042416.html
Copyright © 2020-2023  润新知