高效读写消息队列SafeQueue

来源:互联网 发布:js遍历数组foreach 编辑:程序博客网 时间:2024/06/07 05:21
/******************高效消息队列 读写分离 自旋锁********************/class SpinLock{public:SpinLock() { pthread_spin_init(&m_spinlock, 0); }~SpinLock() { pthread_spin_destroy(&m_spinlock); }private:DISALLOW_COPY_AND_ASSIGN(SpinLock);public:void lock() { pthread_spin_lock(&m_spinlock); }void unlock() { pthread_spin_unlock(&m_spinlock); }private:pthread_spinlock_t m_spinlock;};/*自旋锁就主要用在临界区持锁时间非常短且CPU资源不紧张的情况下 多核最好互斥锁用于临界区持锁时间比较长的操作互斥锁的起始开销要高于自旋锁,但是基本是一劳永逸,临界区持锁时间的大小并不会对互斥锁的开销造成影响,而自旋锁是死循环检测,加锁全程消耗cpu,起始开销虽然低于互斥锁,但是随着持锁时间,加锁的开销是线性增长sleep-waiting busy-waiting*/template <typename T>class SafeQueue{public:SafeQueue():m_pushqueue(NULL),m_popqueue(NULL),m_pushqueueBegin(0),m_popqueueBegin(0),m_pushqueueEnd(0),m_popqueueEnd(0),m_pushqueueMaxSize(1),m_popqueueMaxSize(1){m_pushqueue = new T[1];m_popqueue = new T[1];}~SafeQueue(){delete[] m_pushqueue;delete[] m_popqueue;m_pushqueue = NULL;m_popqueue = NULL;}public:T pop(){m_poplock.lock();if (m_popqueueBegin >= m_popqueueEnd){//无内容可读,交换 读写队列  这里是重点m_pushlock.lock();T* oldpush = m_pushqueue;int32_t maxSize = m_pushqueueMaxSize;int32_t pushend = m_pushqueueEnd;m_pushqueue = m_popqueue;m_pushqueueBegin = 0;m_pushqueueEnd = 0;m_pushqueueMaxSize = m_popqueueMaxSize;m_pushlock.unlock();//写队列,切换到之前的pop队列, 从头开始写,因为前面的都读过了,所以覆盖//最大的长度就是pop的最大长度,//当然就是 上次这里还是写队列 的时候的 maxsize//读队列 切到写队列头 从头开始读 最多读到pushend 读的最大就是写队列的最大 后面很多还没写也有可能m_popqueue = oldpush;m_popqueueBegin = 0;m_popqueueEnd = pushend;m_popqueueMaxSize = maxSize;}//下面开始读if (m_popqueueBegin < m_popqueueEnd){//正常T ret = m_popqueue[m_popqueueBegin++];m_poplock.unlock();return ret;}else{//没东西m_poplock.unlock();return T(0);}}void push(T val){T* oldpos = NULL;m_pushlock.lock();if (m_pushqueueEnd >= m_pushqueueMaxSize){oldpos = m_pushqueue;m_pushqueue = new T[m_pushqueueMaxSize * 2];memcpy(m_pushqueue, oldpos, sizeof(T)*m_pushqueueEnd);m_pushqueueMaxSize *= 2;}m_pushqueue[m_pushqueueEnd++] = val;m_pushlock.unlock();SAFE_DELETE(oldpos);//存储内容拷贝过去 之前的内容需要清掉}private:DISALLOW_COPY_AND_ASSIGN(SafeQueue);private://两个队列,一个用于push 一个用于pop 节省了锁的开销 加快了速度//当读完的时候,换指针,//读指针指向push的队列,从头开始读, //写指针指向pop的队列 之前的已经读过所以覆盖 继续从头开始写T* m_pushqueue;T* m_popqueue;//下面的指针 就是记录读写位置的,方便读写交换队列用int32_t m_pushqueueEnd;int32_t m_popqueueEnd;int32_t m_pushqueueBegin;int32_t m_popqueueBegin;int32_t m_pushqueueMaxSize;int32_t m_popqueueMaxSize;//两个队列的自旋锁 短时间高速适用SpinLock m_pushlock;SpinLock m_poplock;};

原创粉丝点击