无锁队列技术实现

本人在实际项目中用到两种无锁队列,本人还是贴下代码

#ifndef __MPMC_BOUNDED_QUEUE_HPP__ 
#define __MPMC_BOUNDED_QUEUE_HPP__ 
#include <atomic>

template<typename T>
class mpmc_bounded_queue
{
public:
    mpmc_bounded_queue(size_t buffer_size)
        : buffer_(new cell_t[buffer_size])
        , buffer_mask_(buffer_size - 1)
    {
//         assert((buffer_size >= 2) &&
//             ((buffer_size & (buffer_size - 1)) == 0));
        for (size_t i = 0; i != buffer_size; i += 1)
            buffer_[i].sequence_.store(i, std::memory_order_relaxed);
        enqueue_pos_.store(0, std::memory_order_relaxed);
        dequeue_pos_.store(0, std::memory_order_relaxed);
        deque_size = 0;
    }

    ~mpmc_bounded_queue()
    {
        if (NULL != buffer_) {
            delete[] buffer_;
        }        
    }

    bool enqueue(T const& data)
    {
        cell_t* cell;
        size_t pos = enqueue_pos_.load(std::memory_order_relaxed);
        for (;;)
        {
            cell = &buffer_[pos & buffer_mask_];
            size_t seq =
                cell->sequence_.load(std::memory_order_acquire);
            intptr_t dif = (intptr_t)seq - (intptr_t)pos;
            if (dif == 0)
            {
                if (enqueue_pos_.compare_exchange_weak
                (pos, pos + 1, std::memory_order_relaxed))
                    break;
            }
            else if (dif < 0)
                return false;
            else
                pos = enqueue_pos_.load(std::memory_order_relaxed);
        }
        cell->data_ = data;
        cell->sequence_.store(pos + 1, std::memory_order_release);
        deque_size++;
        return true;
    }

    int size()
    {
        return deque_size;
    }

    bool dequeue(T& data)
    {
        cell_t* cell;
        size_t pos = dequeue_pos_.load(std::memory_order_relaxed);
        for (;;)
        {
            cell = &buffer_[pos & buffer_mask_];
            size_t seq =
                cell->sequence_.load(std::memory_order_acquire);
            intptr_t dif = (intptr_t)seq - (intptr_t)(pos + 1);
            if (dif == 0)
            {
                if (dequeue_pos_.compare_exchange_weak
                (pos, pos + 1, std::memory_order_relaxed))
                    break;
            }
            else if (dif < 0)
                return false;
            else
                pos = dequeue_pos_.load(std::memory_order_relaxed);
        }
        data = cell->data_;
        cell->sequence_.store
        (pos + buffer_mask_ + 1, std::memory_order_release);
        deque_size--;
        return true;
    }

private:
    struct cell_t
    {
        std::atomic<size_t>   sequence_;
        T                     data_;
    };

    static size_t const     cacheline_size = 64;
    typedef char            cacheline_pad_t[cacheline_size];

    cacheline_pad_t         pad0_;
    cell_t* const           buffer_;
    size_t const            buffer_mask_;
    cacheline_pad_t         pad1_;
    std::atomic<size_t>     enqueue_pos_;
    cacheline_pad_t         pad2_;
    std::atomic<size_t>     dequeue_pos_;
    cacheline_pad_t         pad3_;
    std::atomic_int                 deque_size;

    mpmc_bounded_queue(mpmc_bounded_queue const&);
    void operator = (mpmc_bounded_queue const&);
};
#endif
 

example:

    typedef mpmc_bounded_queue<void *> lockless_queue_t;
    lockless_queue_t * m_tx_queue[10];

    m_tx_queue[i] = new lockless_queue_t(1024 * 1024 * 4);

//loop要退出必须要把该管理器的内存数据刷进去Mysql
    while (true)
    {
        void* data = NULL;
        bool bRet = m_tx_queue[i]->dequeue(data);

      if(m_exit)

     { return true;}

  }

    bool bRet = m_tx_queue[iMode]->enqueue(pData);

还有另外一种无锁队列实现起来更加简单,但是只能针对一个线程读、另外一个线程写,但是基本上符合很多业务需求,但是这种也有固定缺点,第一无法动态伸缩。

#include <string.h>
#include "unlockqueue.h"

UnlockQueue::UnlockQueue()
:m_pBuffer(NULL)
,m_pHead(NULL)
,m_pTail(NULL)
,m_nSize(0)
{
}

UnlockQueue::UnlockQueue(size_t nSize)
:m_pBuffer(NULL)
,m_pHead(NULL)
,m_pTail(NULL)
,m_nSize(nSize)
{
    Init(nSize);
}

UnlockQueue::~UnlockQueue()
{
    UnInit();
}

bool UnlockQueue::Init(size_t nSize)
{
    if(m_pBuffer != NULL)
    {
        delete [] m_pBuffer;
    }

    m_pBuffer = new char[nSize];
    m_pHead = m_pBuffer;
    m_pTail = m_pBuffer;
    m_nSize = nSize;
    return true;
}

void UnlockQueue::UnInit()
{
    if(m_pBuffer != NULL)
    {
        delete [] m_pBuffer;
        m_pBuffer = NULL;
        m_pHead = NULL;
        m_pTail = NULL;
    } 
}

bool UnlockQueue::Write(const char* pData, size_t nLen)
{
    size_t nDist = (m_pTail + m_nSize - m_pHead);
    size_t nUsed = nDist >= m_nSize ? nDist - m_nSize : nDist;
    if(nLen + 1 + nUsed > m_nSize)
    {
        return false;
    }

    if(m_pTail + nLen >= m_pBuffer + m_nSize)
    {
        size_t nSeg1 = (size_t)(m_pBuffer + m_nSize - m_pTail);
        size_t nSeg2 = nLen - nSeg1;
        memcpy(m_pTail, pData, nSeg1);
        memcpy(m_pBuffer, pData + nSeg1, nSeg2);
        m_pTail = m_pBuffer + nSeg2;
    }
    else
    {
        memcpy(m_pTail, pData, nLen);
        m_pTail += nLen;
    }

    return true;
}

bool UnlockQueue::Read(char* pBuf, size_t nLen)
{
    size_t nDist = (m_pTail + m_nSize - m_pHead);
    size_t nUsed = nDist >= m_nSize ? nDist - m_nSize : nDist;
    if(nLen > nUsed)
    {
        return false;
    }

    if(m_pHead + nLen >= m_pBuffer + m_nSize)
    {
        size_t nSeg1 = (size_t)(m_pBuffer + m_nSize - m_pHead);
        size_t nSeg2 = nLen - nSeg1;
        memcpy(pBuf, m_pHead, nSeg1);
        memcpy(pBuf + nSeg1, m_pBuffer, nSeg2);
        m_pHead = m_pBuffer + nSeg2;
    }
    else
    {
        memcpy(pBuf, m_pHead, nLen);
        m_pHead += nLen;
    }

    return true;
}

bool UnlockQueue::Discard(size_t nLen)

    size_t nDist = (m_pTail + m_nSize - m_pHead);
    size_t nUsed = nDist >= m_nSize ? nDist - m_nSize : nDist;
    if(nLen > nUsed)
    {
        return false;
    }

    if(m_pHead + nLen >= m_pBuffer + m_nSize)
    {
        size_t nSeg1 = (size_t)(m_pBuffer + m_nSize - m_pHead);
        size_t nSeg2 = nLen - nSeg1;
        m_pHead = m_pBuffer + nSeg2;
    }
    else
    {
        m_pHead += nLen;
    }

    return true;
}

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值