/******************高效消息队列 读写分离 自旋锁********************/
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;
};
高效读写消息队列SafeQueue
最新推荐文章于 2022-01-27 15:36:28 发布