/* 循环队列; by dzj, 09.05.04 */ #include "buflog.h" template class CirQueue { public: explicit CirQueue( DsEvent* pNotiEvent/*此参数空时,不通知可读事件,另外:读线程不可无限等待此事件,以免漏掉在没有后续消息时漏掉有效消息*/ ) { m_tail = m_head = 0; m_pNotiEvent = pNotiEvent; } public: ///压元素数组入队列,仅由写线程调用; bool PushEle( T_Ele** pEleArr/*输入元素数组*/, const unsigned int arrNum/*输入数组中有效元素个数*/ ) { if ( NULL == pEleArr ) { NewLog( LOG_LEV_ERROR, "CirQueue::PushEle,输入元素数组空" ); return false; } //计算剩余空间是否足够放入日志,若足够,则放入; unsigned int curhead = m_head;//当前头,该值可能会由于读线程而改变,因此需要保存快照,而m_tail只会由写日志线程改变,因此无需保存; curhead = (curhead < CIR_INNER_SIZE) ? curhead:0; unsigned int cursize = ( curhead <= m_tail ) ? (m_tail-curhead) : ( m_tail + (CIR_INNER_SIZE-curhead) ); unsigned int availsize = CIR_INNER_SIZE - cursize - 1;//可用空间; availsize = (availsize < CIR_INNER_SIZE) ? availsize : 0;//由于head与tail之间要留一空格避免写过头,因此实际可用空间小于INNER_BUF_SIZE; if ( arrNum > availsize ) { //可用空间不足以存放输入数组; NewLog( LOG_LEV_ERROR, "CirQueue::PushEle, 有效%d,可用%d,内部缓存空间不足!!!!!!!!!!!!!", arrNum, availsize ); //assert(false); return false; } //输入数组可以放下,拷贝之 unsigned int availtailsize = CIR_INNER_SIZE - m_tail;//尾部有效大小,拷贝不要越过数组尾部 if ( availtailsize >= arrNum ) { //至尾部空间足够存放 memcpy( &(m_innerArr[m_tail]), (pEleArr), arrNum*sizeof(T_Ele*) ); m_tail += arrNum; } else { //尾部空间不够存放,则一部放至尾部,一部拷至头部; memcpy( &(m_innerArr[m_tail]), pEleArr, availtailsize*sizeof(T_Ele*) ); memcpy( &(m_innerArr[0]), pEleArr+availtailsize, (arrNum-availtailsize)*sizeof(T_Ele*) ); m_tail = (arrNum-availtailsize);//从头开始数起存放的元素个数,即为尾部位置(0起,也就是下一个可写位置); } m_tail = (m_tail < CIR_INNER_SIZE) ? m_tail:0; if ( NULL != m_pNotiEvent ) { cursize += arrNum;//目前缓冲的元素数量; if ( cursize >= NOTIFY_BIAS ) { m_pNotiEvent->SignalEvent();//激活可能在等待的读线程; } } return true; } ///弹元素数组出队列,仅由读线程调用; bool PopEle( T_Ele** pEleArr/*输出元素数组*/, const unsigned int eleArrSize/*输出数组中可以存储的元素个数*/, int& outNum/*真正输出的元素个数*/ ) { outNum = 0;//初始,无元素可供输出; if ( NULL == pEleArr ) { NewLog( LOG_LEV_ERROR, "CirQueue::PopEle, 输出元素数组空" ); return false; } unsigned int curtail = m_tail;//当前尾,该值可能会由于写线程PushEle而改变,因此需要保存快照,而m_head只会由读线程改变,因此无需保存; curtail = (curtail < CIR_INNER_SIZE) ? curtail:0; //取得当前内部有效元素个数; unsigned int cursize = ( m_head <= curtail ) ? (curtail-m_head) : ( curtail + (CIR_INNER_SIZE-m_head) ); if ( cursize <= 0 ) { //当前没有可写日志; return true; } unsigned int togetnum = cursize;//可以的话,取所有可取元素; if ( eleArrSize < cursize ) { //输出缓存不够,输出eleArrSize个元素先; togetnum = eleArrSize; } //有待输出元素; if ( m_head <= curtail ) { //可输出元素全部在尾部; memcpy( pEleArr, &(m_innerArr[m_head]), togetnum*sizeof(T_Ele*) ); m_head += togetnum; } else { //可输出部分绕过了尾部; unsigned int tailsize = CIR_INNER_SIZE - m_head;//尾部可取字符数; if ( tailsize >= togetnum ) { //尾部可取元素数大于等于欲取元素数; memcpy( pEleArr, &(m_innerArr[m_head]), togetnum*sizeof(T_Ele*) ); m_head += togetnum; } else { //尾部可取元素数不足欲取元素数; memcpy( pEleArr, &(m_innerArr[m_head]), tailsize*sizeof(T_Ele*) );//先取完尾部可取元素; memcpy( &(pEleArr[tailsize]), &(m_innerArr[0]), (togetnum-tailsize)*sizeof(T_Ele*) );//不足部分头部继续取; m_head = togetnum-tailsize; } } m_head = (m_head < CIR_INNER_SIZE) ? m_head:0; outNum = togetnum;//输出的有效元素个数; return true; } private: unsigned int m_head;//头,只由读线程修改; unsigned int m_tail;//尾,只由写线程修改; T_Ele* m_innerArr[CIR_INNER_SIZE]; private: DsEvent* m_pNotiEvent; };