关于无锁队列的使用

前段时间无意中想到了无锁队列,于是实现之,实现代码如下:
template<class T0>
bool CUnlockQue<T0>::Push(T0 &tValue, int nWaitTime)
{
	struct timespec TimeWait;

	//已经有足够多的push操作向列队不同位置写入数据
	while (0 >= AtomDec(m_nAbleWriteCount, 1))
	{
		AtomAdd(m_nAbleWriteCount, 1);

		TimeWait.tv_sec 	= time(NULL) + nWaitTime;
		TimeWait.tv_nsec 	= 0;

		// 等待唤醒
		pthread_mutex_lock(&m_Mutex);
	    if (ETIMEDOUT == pthread_cond_timedwait(&m_CondWait, &m_Mutex, &TimeWait)) // 超时
	    {
	    	pthread_mutex_unlock(&m_Mutex);
	    	return false;
	    }

		pthread_mutex_unlock(&m_Mutex);
	}

	int nPushPos = AtomAdd(m_nPush, 1);
	nPushPos = nPushPos % m_nMaxCap;

	/*
		只有在NPop并发情况下,因Pop无序完成,第一个位置的Pop未完成,后面的Pop就先完成提示有空位
		因为该类只允许1对N,所以必然是单线程Push,所以条件内push控制变量不需要原子操作
		进行不停的尝试,找到"Pop“完成
	 */
	while (!m_VecElement[nPushPos].bIsEmpty)
	{
		/*
		m_nPush --;
		m_nWriteAbleCount ++;
		return false;
		*/
	}

	m_VecElement[nPushPos].Element 	= tValue;
	m_VecElement[nPushPos].bIsEmpty = false;

	AtomAdd(m_nAbleReadCount, 1);

	return true;
}

template<class T0>
bool CUnlockQue<T0>::Pop(T0 &tValue)
{
	if (0 >= m_nAbleReadCount)
	{
		return false;//空列队
	}
	if ( 0 >= AtomDec(m_nAbleReadCount, 1)) //已经有足够多的pop操作读取列队不同位置的数据
	{
		AtomAdd(m_nAbleReadCount, 1);
		return false;
	}

	pthread_cond_broadcast(&m_CondWait);

	int nPopPos = AtomAdd(m_nPop, 1);
	nPopPos = m_nPop % m_nMaxCap;

	while (m_VecElement[nPopPos].bIsEmpty)
	{
		/*
		m_nAbleReadCount ++;
		m_nPop --;
		*/
	}

	tValue = m_VecElement[nPopPos].Element;
	m_VecElement[nPopPos].bIsEmpty = true;

	AtomAdd(m_nAbleWriteCount, 1);

	return true;
}

template<class T0>
int CUnlockQue<T0>::AtomAdd(int &nElement, int nValue)
{
	return __sync_fetch_and_add(&nElement, nValue);
}

template<class T0>
int CUnlockQue<T0>::AtomDec(int &nElement, int nValue)
{
	nValue *= -1;
	return __sync_fetch_and_add(&nElement, nValue);
}

说明:

1: 通过__sync_fetch_and_add来实现无所队列,(还有可以用cas指令来实现无锁队列,不知道效果如何)

2: 这里本想用条件变量来实现当队列满阻塞等待,发现无法实现之。(不知道是否有好方法),于是乎采取了轮训方法进行实现等待(消耗CPU)


测试:

void* thread_input(void *lpParameter)
{
	int nValue;


	while (1)
	{
		nValue = __sync_fetch_and_add(&g_CalcNums, 1);
		if (!g_Que.Push(nValue, 5))
		{
			LOG_APP_WARN("Value=%d,Push Failed!", nValue);
		}
	}


	return (void *)1;
}


void *thread_OutPut(void *lpParameter)
{
	int nValue;
	while (1)
	{
		if (!g_Que.Pop(nValue))
		{
			LOG_APP_WARN("Empty");
			continue;
		}


		LOG_APP_DEBUG("Value=%d", nValue);
	}


	return (void *)1;
}

结果:

分别开了3个线程push数据,1个线程pop读数据。测试结果:约450000/s,,对于无锁队列我感觉很奇怪,测试效率貌似很低。

于是采用加锁的push方法:Pop线程采用swap机制。测试结果:约2351230/s。


结论

无锁队列的效率怎么这么低,照理说不应该。__sync_fetch_and_add其实是个原子指令,gcc独有的。猜想类似于锁。所以无锁队列的"锁"很多,个人觉得如果还是采用“锁交换机制”更好。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值