单向循环链表实现RingBuffer

Posted fulianzhou

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单向循环链表实现RingBuffer相关的知识,希望对你有一定的参考价值。

        一般我们用的RingBuffer都是用数组或vector实现,用读指针与写指针来控制RingBuffer的输入与输出。用不同的线程来Push与Pull,一般情况下这种结构是非常高效的,无需加锁。但是当Pull处理线程比Push处理线程慢得多的时候,Push就会等待RingBuffer非空;等待有时候会很耗费时间,运行的越久累积的时延就越高。

        所以用单向循环链表来替代数组或vector,当RingBuffer满时就插入一个新的位置,减少Push等待时间。但是如果Pull处理的时间太长,Push又不断有新数据插入,就会导致RingBuffer太长,占用过多资源,所以可以加一个计数器来控制RingBuffer的最大长度。

listringbuffer.h

#ifndef _LIST_RINGBUFFER_H_
#define _LIST_RINGBUFFER_H_
#include <stdint.h>


template <typename T>
struct LNode
{
    T data;
    LNode* next;

    LNode() :next(NULL){}
    LNode(const T& item) : next(NULL), data(item){}
};

template <typename T>
class ListRingBuffer
{
private:
    uint32_t m_cap;
    LNode<T>* m_root;
    LNode<T>* m_posr;
    LNode<T>* m_posw;
public:
    ListRingBuffer(int initsize = 10)
        : m_root(NULL),
        m_posr(NULL),
        m_posw(NULL),
        m_cap(initsize)
    {
        if (initsize < 10)
        {
            initsize = 10;
            m_cap = initsize;
        }

        m_root = new LNode<T>;
        //m_root->data = -1;

        LNode<T>* pTail = m_root;

        for (int i = 0; i < initsize; i++)
        {
            LNode<T>* pNode = new LNode<T>;
            //pNode->data = -1;
            pNode->next = m_root;
            m_root = pNode;
        }

        m_posr = m_posw = m_root;
        pTail->next = m_root;
    }

    ~ListRingBuffer()
    {
        while (m_root)
        {
            LNode<T>* pNode = m_root;
            m_root = m_root->next;

            if (pNode)
            {
                delete pNode;
                pNode = NULL;
            }
        }
    }

public:
    int GetCap() { return m_cap; }

    void Push(const T &data)
    {
        /* buffer is full */
        if (m_posw->next == m_posr)
        {
            m_posw->data = data;

            LNode<T>* pNode = new LNode<T>;
            //pNode->data = -1;
            pNode->next = m_posw->next;
            m_posw->next = pNode;

            m_posw = m_posw->next;
            m_cap += 1;
            printf("");
            //printf("cap = %d\\n", m_cap);
        }
        else
        {
            m_posw->data = data;
            m_posw = m_posw->next;
        }
    }

    bool Pull(T& data)
    {
        if (m_posr == m_posw)
        {
            return false;
        }

        data = m_posr->data;
        m_posr = m_posr->next;

        return true;
    }
};
#endif

main.cpp

#include <stdio.h>
#include <Windows.h>

#include "listringbuffer.h"


DWORD WINAPI PushThread(LPVOID lpParam)
{
    ListRingBuffer<int>* pbuff = (ListRingBuffer<int>*)lpParam;
    if (!pbuff)
    {
        return -1;
    }

    int counter = 1;
    while (true)
    {
        pbuff->Push(counter);
        counter++;

        //pbuff->Travel();
        Sleep(1);
    }

    return 0;
}

DWORD WINAPI PullThread(LPVOID lpParam)
{
    ListRingBuffer<int>* pbuff = (ListRingBuffer<int>*)lpParam;
    if (!pbuff)
    {
        return -1;
    }

    int idx = 1;
    while (true)
    {
        int data = 0;
        if (!pbuff->Pull(data))
        {
            continue;
        }
        printf("idx = %d data=%d cap=%d\\n", idx, data, pbuff->GetCap());

        if (idx != data)
        {
            break;
        }

        idx++;
    }

    return 0;
}


int main(int argc, char* argv[])
{
    ListRingBuffer<int> listbuffer;

    HANDLE handles[2] = { NULL };

    DWORD dwPid;
    handles[0] = CreateThread(NULL, 0, PushThread, &listbuffer, 0, &dwPid);
    if (!handles[0])
    {
        printf("create push thread failed, errno:%s\\n", GetLastError());
    }

    handles[1] = CreateThread(NULL, 0, PullThread, &listbuffer, 0, &dwPid);
    if (!handles[1])
    {
        printf("create push thread failed, errno:%s\\n", GetLastError());
    }

    WaitForMultipleObjects(2, handles, TRUE, INFINITE);

    return 0;
}


 

以上是关于单向循环链表实现RingBuffer的主要内容,如果未能解决你的问题,请参考以下文章

单向循环链表实现RingBuffer

java实现单向循环链表

单向循环链表

(java实现)单向循环链表

单向循环链表

python中的单向循环链表实现