一个高速无锁循环队列的实现。
需要注意的是:
(1)队列的大小(m_lMaxQueueSize)应该足够的大,避免处理不过来时,找半天找不到空位置。
(2)还有一点是这种队列在push数据足够快时效率高点,不然pop时就阻塞了,改善的方式就是使用费阻塞的方式,判断几次没有就跳出去,还有这种队列也就在push数据足够快时效率高点,不然判断的次数就多了。
(3)使用了原子操作的锁
(4)需要优化的的是数值开始与结束之间长度小于阈值就不取。
代码如下:
// 临界锁,线程安全
// 必须要有一个不会用的空值
typedef unsigned int var_4;
typedef unsigned long var_u8;
template <class T_Key> //队列里的值
class CQueue_Lockfree
{
public:
CQueue_Lockfree()
{
m_lMaxQueueSize = -1;
m_tpQueue = NULL; //队列的内存
m_lBegPos = 0; //队列的开始位置
m_lEndPos = 0; //队列的结束位置
};
~CQueue_Lockfree()
{
if(m_tpQueue)
delete m_tpQueue;
};
var_4 InitQueue(var_4 lMaxQueueSize, T_Key null)//null为空的值(目前为0)
{
m_lMaxQueueSize = lMaxQueueSize;
m_tpQueue = new T_Key[m_lMaxQueueSize];
if(m_tpQueue == NULL)
return -1;
m_lBegPos = 0;
m_lEndPos = 0;
m_null = null;
for( var_4 i = 0; i < lMaxQueueSize; i++ )
{
m_tpQueue[i] = null;
}
return 0;
};
void ResetQueue()
{
m_lBegPos = 0;
m_lEndPos = 0;
};
void ClearQueue()
{
if(m_tpQueue)
{
delete m_tpQueue;
m_tpQueue = NULL;
}
m_lMaxQueueSize = -1;
m_lBegPos = 0;
m_lEndPos = 0;
};
void PushData(T_Key tKey)
{
register var_u8 cnt = 1;
var_u8 pos = fetch_and_add(&m_lEndPos, cnt)%m_lMaxQueueSize; //队列的m_lEndPos位置下一个位置
while( m_null != m_tpQueue[pos] ) //等到该位置为空才能放数值
cp_sleep(1);
m_tpQueue[pos] = tKey;
};
T_Key PopData()
{
register var_u8 cnt =1;
var_u8 pos = fetch_and_add(&m_lBegPos, cnt)%m_lMaxQueueSize; //队列的m_lBegPos位置下一个位置
T_Key *p = m_tpQueue + pos;
while( m_null == *p ) //等到该位置不为空才能取数值
cp_sleep(1);
T_Key ret = *p;
*p = m_null;
return ret;
};
private:
var_4 m_lMaxQueueSize;
T_Key* m_tpQueue;
T_Key m_null;
var_u4 m_lBegPos;
var_u4 m_lEndPos;
};
别人的测试结果,这种方式比用锁少了40%。
10亿次放入和读取,10线程花费200秒。
测试说加了阈值判断后说是8核1.5GHz花了88秒,没加前是
24核机器200秒
vendor_id : GenuineIntel
cpu family