使用循环缓冲区模拟图像数据采集及绘制

	首先是基于QWaitCondition的线程同步,QWaitCondition提供了一种改进线程同步的方法,通过于QMutex结合,可以使一个线程在满足一定条
件时通知其他多个线程,使他们做出响应,相对于互斥量效率高一些。
	本示例程序基于“生产者/消费者”模型,采集线程相当于生产者,读取线程相当于消费者,主线程完成图像数据的绘制。在实际应用中,通常使用
缓冲区的方式减少动态申请和释放内存的繁琐及消耗,也属于空间换时间的一种策略。核心代码如下:
//写入数据
int CCycleBuffer::write(char* buf, int count)  
{ 
	mutex.lock();
	if (count <= 0)
	{
		mutex.unlock();
		return 0;
	}
	m_bEmpty = false;  
	// 缓冲区已满,不能继续写入  
	if(m_bFull)   
	{  
		mutex.unlock();
		return 0;  
	}  
	else if(m_nReadPos == m_nWritePos) // 缓冲区为空时  
	{  
		/*                          == 内存模型 == 
				 (empty)             m_nReadPos                (empty)                       
		|----------------------------------|-----------------------------------------| 
									m_nWritePos        m_nBufSize 
		*/  
		int leftcount = m_nBufSize - m_nWritePos;  
		if(leftcount > count)  
		{  
			memcpy(m_pBuf + m_nWritePos, buf, count);  
			m_nWritePos += count;  
			m_bFull = (m_nWritePos == m_nReadPos); 
			//qDebug() << "m_nReadPos == m_nWritePos  leftcount > count  writepos: " << m_nWritePos << " readpos: " << m_nReadPos;
			bufferNotEmpty.wakeAll();
			mutex.unlock();
			return count;  
		}  
		else  
		{  
			memcpy(m_pBuf + m_nWritePos, buf, leftcount);  
			m_nWritePos = (m_nReadPos > count - leftcount) ? count - leftcount : m_nWritePos;  
			memcpy(m_pBuf, buf + leftcount, m_nWritePos);  
			//qDebug() << "m_nReadPos == m_nWritePos  leftcount <= count  writepos: " << m_nWritePos << " readpos: " << m_nReadPos;
			m_bFull = (m_nWritePos == m_nReadPos);  
			bufferNotEmpty.wakeAll();
			mutex.unlock();
			return leftcount + m_nWritePos;  
		}  
	}   
	else if(m_nReadPos < m_nWritePos) // 有剩余空间可写入  
	{  
		/*                           == 内存模型 == 
			(empty)                 (data)                     (empty) 
		|-------------------|----------------------------|---------------------------| 
					m_nReadPos                m_nWritePos       (leftcount)            
		*/  
		// 剩余缓冲区大小(从写入位置到缓冲区尾)  
		int leftcount = m_nBufSize - m_nWritePos;
		if(leftcount > count)   // 有足够的剩余空间存放  
		{  
			memcpy(m_pBuf + m_nWritePos, buf, count);  
			m_nWritePos += count;  
			m_bFull = (m_nReadPos == m_nWritePos);  
			//qDebug() << "m_nReadPos < m_nWritePos  leftcount > count  writepos: " << m_nWritePos << " readpos: " << m_nReadPos;
			assert(m_nReadPos <= m_nBufSize);  
			assert(m_nWritePos <= m_nBufSize); 
			bufferNotEmpty.wakeAll();
			mutex.unlock();
			return count;  
		}  
		else       // 剩余空间不足  
		{  
			// 先填充满剩余空间,再回头找空间存放  
			memcpy(m_pBuf + m_nWritePos, buf, leftcount); 
			m_nWritePos = (m_nReadPos >= count - leftcount) ? count - leftcount : m_nReadPos;  
			memcpy(m_pBuf, buf + leftcount, m_nWritePos);  
			m_bFull = (m_nReadPos == m_nWritePos); 
			//qDebug() << "m_nReadPos < m_nWritePos  leftcount <= count  writepos: " << m_nWritePos << " readpos: " << m_nReadPos;
			assert(m_nReadPos <= m_nBufSize);  
			assert(m_nWritePos <= m_nBufSize); 
			bufferNotEmpty.wakeAll();
			mutex.unlock();
			return leftcount + m_nWritePos;  
		}  
	}  
	else  
	{  
		/*                          == 内存模型 == 
			(unread)                 (read)                     (unread) 
		|-------------------|----------------------------|---------------------------| 
					 m_nWritePos    (leftcount)    m_nReadPos                       
		*/  
		int leftcount = m_nReadPos - m_nWritePos;  
		if(leftcount > count)  
		{  
			// 有足够的剩余空间存放  
			memcpy(m_pBuf + m_nWritePos, buf, count);  
			m_nWritePos += count;  
			m_bFull = (m_nReadPos == m_nWritePos);  
			//qDebug() << "m_nReadPos > m_nWritePos  leftcount > count  writepos: " << m_nWritePos << " readpos: " << m_nReadPos;
			assert(m_nReadPos <= m_nBufSize);  
			assert(m_nWritePos <= m_nBufSize);  
			bufferNotEmpty.wakeAll();
			mutex.unlock();
			return count;  
		}  
		else  
		{  
			// 剩余空间不足时要丢弃后面的数据  
			memcpy(m_pBuf + m_nWritePos, buf, leftcount);  
			m_nWritePos += leftcount;  
			m_bFull = (m_nReadPos == m_nWritePos);  
			//qDebug() << "m_nReadPos > m_nWritePos  leftcount <= count  writepos: " << m_nWritePos << " readpos: " << m_nReadPos;
			assert(m_bFull);  
			assert(m_nReadPos <= m_nBufSize);  
			assert(m_nWritePos <= m_nBufSize); 
			bufferNotEmpty.wakeAll();
			mutex.unlock();
			return leftcount;  
		}  
	}  
} 
//读入数据
int CCycleBuffer::read(char* buf, int count)  
{  
	mutex.lock();
	if (count <= 0)
	{
		mutex.unlock();
		return 0;
	}
	m_bFull = false;  
	if(m_bEmpty)       // 缓冲区空,不能继续读取数据  
	{  
		mutex.unlock();
		return 0;  
	}  
	else if(m_nReadPos == m_nWritePos)   // 缓冲区满时  
	{  
		/*                          == 内存模型 == 
		 (data)          m_nReadPos                (data)     
		|--------------------------------|--------------------------------------------| 
			 m_nWritePos         m_nBufSize 
		*/  
		int leftcount = m_nBufSize - m_nReadPos;  
		if(leftcount > count)  
		{  
			memcpy(buf, m_pBuf + m_nReadPos, count);  
			m_nReadPos += count;  
			m_bEmpty = (m_nReadPos == m_nWritePos);  
			bufferNotFull.wakeAll();
			mutex.unlock();
			return count;  
		}  
		else  
		{  
			memcpy(buf, m_pBuf + m_nReadPos, leftcount);  
			m_nReadPos = (m_nWritePos > count - leftcount) ? count - leftcount : m_nWritePos;  
			memcpy(buf + leftcount, m_pBuf, m_nReadPos);  
			m_bEmpty = (m_nReadPos == m_nWritePos);  
			bufferNotFull.wakeAll();
			mutex.unlock();
			return leftcount + m_nReadPos;  
		}  
	}  
	else if(m_nReadPos < m_nWritePos)   // 写指针在前(未读数据是连接的)  
	{  
		/*                          == 内存模型 == 
			(read)                 (unread)                      (read)     
		|-------------------|----------------------------|---------------------------| 
					m_nReadPos                m_nWritePos                     m_nBufSize 
		*/  
		int leftcount = m_nWritePos - m_nReadPos;  
		int c = (leftcount > count) ? count : leftcount;  
		memcpy(buf, m_pBuf + m_nReadPos, c);  
		m_nReadPos += c;  
		m_bEmpty = (m_nReadPos == m_nWritePos);  
		assert(m_nReadPos <= m_nBufSize);  
		assert(m_nWritePos <= m_nBufSize);  
		bufferNotFull.wakeAll();
		mutex.unlock();
		return c;  
	}  
	else          // 读指针在前(未读数据可能是不连接的)  
	{  
		/*                          == 内存模型 == 
			  (unread)                (read)                      (unread) 
		|-------------------|----------------------------|---------------------------| 
					 m_nWritePos                  m_nReadPos                  m_nBufSize 
		*/  
		int leftcount = m_nBufSize - m_nReadPos;  
		if(leftcount > count)   // 未读缓冲区够大,直接读取数据  
		{  
			memcpy(buf, m_pBuf + m_nReadPos, count);  
			m_nReadPos += count;  
			m_bEmpty = (m_nReadPos == m_nWritePos);  
			assert(m_nReadPos <= m_nBufSize);  
			assert(m_nWritePos <= m_nBufSize); 
			bufferNotFull.wakeAll();
			mutex.unlock();
			return count;  
		}  
		else       // 未读缓冲区不足,需回到缓冲区头开始读  
		{  
			memcpy(buf, m_pBuf + m_nReadPos, leftcount);  
			m_nReadPos = (m_nWritePos >= count - leftcount) ? count - leftcount : m_nWritePos;  
			memcpy(buf + leftcount, m_pBuf, m_nReadPos);  
			m_bEmpty = (m_nReadPos == m_nWritePos);  
			assert(m_nReadPos <= m_nBufSize);  
			assert(m_nWritePos <= m_nBufSize);
			bufferNotFull.wakeAll();
			mutex.unlock();
			return leftcount + m_nReadPos;  
		}    
	}  
} 
//获取有效长度
int CCycleBuffer::getUsedSize()  
{  
	mutex.lock();
	int size = 0;
	if(m_bEmpty)  
	{  
		size = 0;
	}  
	else if(m_bFull)  
	{  
		size = m_nBufSize;
	}  
	else if(m_nReadPos < m_nWritePos)  
	{  
		size = m_nWritePos - m_nReadPos;
	}  
	else  
	{  
		size = m_nBufSize - m_nReadPos + m_nWritePos;
	}  
	mutex.unlock();
	return size;
}
//获取空余长度
int CCycleBuffer::getFreeSize() 
{  
	mutex.lock();
	int size = 0;
	if(m_bEmpty)  
	{  
		size =  m_nBufSize;
	}  
	else if(m_bFull)  
	{  
		size = 0;
	}  
	else if(m_nReadPos > m_nWritePos)  
	{  
		size = m_nReadPos - m_nWritePos;
	}  
	else  
	{  
		size = m_nBufSize - m_nWritePos + m_nReadPos;
	}  
	mutex.unlock();
	return size;
}
//重新设定缓冲区大小
bool CCycleBuffer::setBufferSize(int size, bool copy)
{
	mutex.lock();
	//若已有空间,释放掉。开辟新缓冲区,并进行拷贝旧数据
	if (m_pBuf != 0)
	{
		//新开辟缓冲区
		char* buf = new char(size);
		//若需要拷贝
		if (copy)
		{
			if (size <= m_nBufSize)
			{
				//拷贝旧数据
				memcpy(buf, m_pBuf, size);
				//qDebug()<<"CCycleBuffer::setBufferSize,重置缓冲区,开辟空间小于原先旧空间,会丢失数据。";
			}
			else
				memcpy(buf, m_pBuf, m_nBufSize);
		}
		//释放旧缓冲区
		delete []m_pBuf;
		//指向新缓冲区
		m_pBuf = buf;
		//重置缓冲区大小
		m_nBufSize = size;
	}
	//若没有缓冲区,则开辟缓冲区
	else
	{
		//新开辟缓冲区
		m_pBuf = new char(size);
		//赋值缓冲区大小
		m_nBufSize = size;
	}
	//重置标志位
	m_bEmpty = true;
	m_bFull = false;
	m_nBufSize = size;
	m_nReadPos = 0;
	m_nWritePos = 0;
	bufferNotFull.wakeAll();
	mutex.unlock();
	if (m_pBuf != 0)
		return true;
	else
		return false;
}
//清空缓冲区
bool CCycleBuffer::clearBuffer()
{
	mutex.lock();
	//重置标志位
	m_bEmpty = true;
	m_bFull = false;
	m_nReadPos = 0;
	m_nWritePos = 0;
	bufferNotFull.wakeAll();
	mutex.unlock();
	return true;
}
//设置阻塞
void CCycleBuffer::waitNotEmpty()
{
	mutex.lock();
	bufferNotEmpty.wait(&mutex,5000);
	mutex.unlock();
}
void CCycleBuffer::waitNotFull()
{
	mutex.lock();
	bufferNotFull.wait(&mutex,5000);
	mutex.unlock();
}
//声明函数
void enqueue(char* buffer, int length);//进栈
extern "C" void dequeue(char* buffer, int length);//出栈
void enqueue(char* buffer, int length) {
	if (S_CCycleBuffer->getFreeSize() >= 1280*996 * 2/*DataLength*/)
	{
		S_CCycleBuffer->write((char*)buffer, length);
	}
	else//如果没有这个等待,会有很多空循环,CPU会很高
	{
		S_CCycleBuffer->waitNotFull();
	}
}
void dequeue(char* buffer, int length) {
	if (S_CCycleBuffer->getUsedSize() >= 1280 * 996 * 2)
	{
		S_CCycleBuffer->read(buffer, length);//
		//qDebug() <<"【ReadThread】读完后,循环缓冲区有效数据:" << S_CCycleBuffer->getUsedSize()<<"B.";
		}
	else//如果没有这个等待,就会有很多空循环,CPU会很高。
	{
		//qDebug() << "【ReadThread】S_CCycleBuffer->waitNotEmpty()---------------";
		S_CCycleBuffer->waitNotEmpty();
		return;
	}
}

示例:
在这里插入图片描述
动态效果图:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值