Как Вы реализуете кольцевой буфер в C?

Быстрый поиск похожих проблем в StackOverflow позволил получить полезных ссылок . Тем не менее, это, вероятно, не лучший форум для того, чтобы задавать этот вопрос, поскольку сообщество Stackoverflow в основном зарезервировано для вопросов, ориентированных на разработчиков. Предполагая, что вышеизложенное не решит вашу проблему, настоятельно рекомендуем перенаправить ваш вопрос на форум MSDN Portal Management Portal . Надеюсь, это поможет.

66
задан paxdiablo 6 May 2009 в 01:52
поделиться

4 ответа

Can you enumerate the types needed at the time you code up the buffer, or do you need to be able to add types at run time via dynamic calls? If the former, then I would create the buffer as a heap-allocated array of n structs, where each struct consists of two elements: an enum tag identifying the data type, and a union of all the data types. What you lose in terms of extra storage for small elements, you make up in terms of not having to deal with allocation/deallocation and the resulting memory fragmentation. Then you just need to keep track of the start and end indices that define the head and tail elements of the buffer, and make sure to compute mod n when incrementing/decrementing the indices.

9
ответ дан 24 November 2019 в 15:00
поделиться

Простая реализация может состоять из:

  • буфера, реализованного в виде массива размера n, любого необходимого вам типа
  • указателя чтения или индекса (в зависимости от того, что более эффективно для ваш процессор)
  • Указатель записи или индекс
  • Счетчик, указывающий, сколько данных находится в буфере (выводится из указателей чтения и записи, но быстрее отслеживает их отдельно)

Каждый раз, когда вы пишете данные, вы переместите указатель записи и увеличьте счетчик. Когда вы читаете данные, вы увеличиваете указатель чтения и уменьшаете счетчик. Если любой указатель достигает n, установите его на ноль.

Вы не можете писать, если counter = n. Вы не можете прочитать, если counter = 0.

2
ответ дан 24 November 2019 в 15:00
поделиться

The simplest solution would be to keep track of the item size and the number of items, and then create a buffer of the appropriate number of bytes:

typedef struct circular_buffer
{
    void *buffer;     // data buffer
    void *buffer_end; // end of data buffer
    size_t capacity;  // maximum number of items in the buffer
    size_t count;     // number of items in the buffer
    size_t sz;        // size of each item in the buffer
    void *head;       // pointer to head
    void *tail;       // pointer to tail
} circular_buffer;

void cb_init(circular_buffer *cb, size_t capacity, size_t sz)
{
    cb->buffer = malloc(capacity * sz);
    if(cb->buffer == NULL)
        // handle error
    cb->buffer_end = (char *)cb->buffer + capacity * sz;
    cb->capacity = capacity;
    cb->count = 0;
    cb->sz = sz;
    cb->head = cb->buffer;
    cb->tail = cb->buffer;
}

void cb_free(circular_buffer *cb)
{
    free(cb->buffer);
    // clear out other fields too, just to be safe
}

void cb_push_back(circular_buffer *cb, const void *item)
{
    if(cb->count == cb->capacity){
        // handle error
    }
    memcpy(cb->head, item, cb->sz);
    cb->head = (char*)cb->head + cb->sz;
    if(cb->head == cb->buffer_end)
        cb->head = cb->buffer;
    cb->count++;
}

void cb_pop_front(circular_buffer *cb, void *item)
{
    if(cb->count == 0){
        // handle error
    }
    memcpy(item, cb->tail, cb->sz);
    cb->tail = (char*)cb->tail + cb->sz;
    if(cb->tail == cb->buffer_end)
        cb->tail = cb->buffer;
    cb->count--;
}
73
ответ дан 24 November 2019 в 15:00
поделиться
// Note power of two buffer size
#define kNumPointsInMyBuffer 1024 

typedef struct _ringBuffer {
    UInt32 currentIndex;
    UInt32 sizeOfBuffer;
    double data[kNumPointsInMyBuffer];
} ringBuffer;

// Initialize the ring buffer
ringBuffer *myRingBuffer = (ringBuffer *)calloc(1, sizeof(ringBuffer));
myRingBuffer->sizeOfBuffer = kNumPointsInMyBuffer;
myRingBuffer->currentIndex = 0;

// A little function to write into the buffer
// N.B. First argument of writeIntoBuffer() just happens to have the
// same as the one calloc'ed above. It will only point to the same
// space in memory if the calloc'ed pointer is passed to
// writeIntoBuffer() as an arg when the function is called. Consider
// using another name for clarity
void writeIntoBuffer(ringBuffer *myRingBuffer, double *myData, int numsamples) {
    // -1 for our binary modulo in a moment
    int buffLen = myRingBuffer->sizeOfBuffer - 1;
    int lastWrittenSample = myRingBuffer->currentIndex;

    int idx;
    for (int i=0; i < numsamples; ++i) {
        // modulo will automagically wrap around our index
        idx = (i + lastWrittenSample) & buffLen; 
        myRingBuffer->data[idx] = myData[i];
    }

    // Update the current index of our ring buffer.
    myRingBuffer->currentIndex += numsamples;
    myRingBuffer->currentIndex &= myRingBuffer->sizeOfBuffer - 1;
}

Пока длина кольцевого буфера равна степени двойки, невероятно быстрая двоичная операция «&» будет обертывать ваш индекс за вас. В моем приложении я показываю пользователю сегмент звука из кольцевого буфера звука, полученного с микрофона.

Я всегда убеждаюсь, что максимальное количество звука, которое может отображаться на экране, намного меньше размера кольцевого буфера. В противном случае вы можете читать и писать из одного и того же фрагмента. Скорее всего, это вызовет странные артефакты на экране.

15
ответ дан 24 November 2019 в 15:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: