前言
本篇讲解项目中队列的应用及注意点。
项目为君正方案家庭安防ptz ipc的IVS模块(算法处理)。使用队列来管理算法获取的消息。
代码
/*消息数据*/
typedef struct
{
LUX_BASE_ALGOQUE_TYPE_EN type;
/*MOVE DETECT*/
int retRoi; /*是否探测到*/
int detcount; /*检测出移动区域的宫格数量*/
LUX_BASE_MOVE_REGINFO_ST rectInfo; /*检测初移动区域信息*/
/*PERSON DETECT*/
int rectcnt; /*识别人形数量*/
LUX_PERSON_INFO person[20]; /*识别出的人形信息*/
/*PERSON TRACKER*/
void *IVSResult; /*IVS算法处理结果*/
void *pCallBackInfo; /*回调函数入口*/
CallBackFunc pCallBackFunc; /*回调函数*/
}LUX_BASE_IVSDATA_ST;
/*队列结构体*/
typedef struct
{
LUX_BASE_IVSDATA_ST IVSDetData[LUX_BASE_QUE_MAXSIZE];
int rIdx;//read index
int wIdx;//write indes
}LUX_BASE_IVSQUE_ST;
puch&pop
/**
* @description: 消息队列有效数据长度
* @param [in] pQue 队列
* @return 0 成功,非零失败
*/
int QueueLength(LUX_BASE_IVSQUE_ST *pQue)
{
if(NULL == pQue)
{
printf("%s:%d Point NULL!\n", __func__, __LINE__);
return BASE_COMM_ERR;
}
return (pQue->wIdx - pQue->rIdx+ LUX_BASE_QUE_MAXSIZE) % LUX_BASE_QUE_MAXSIZE;
}
/**
* @description: 消息入队
* @param [in] pQue 队列
* @param [in] pInData 出队数据
* @return 0 成功,非零失败
*/
int PushQueue(LUX_BASE_IVSQUE_ST *pQue, LUX_BASE_IVSDATA_ST *pInData)
{
if(NULL == pQue)
{
printf("%s:%d Point NULL!\n", __func__, __LINE__);
return BASE_COMM_ERR;
}
/*判满*/
if((pQue->wIdx+ 1) % LUX_BASE_QUE_MAXSIZE == pQue->rIdx)
{
return 0;
}
Thread_Mutex_Lock(&g_ivs_que_mux);
memcpy(&pQue->IVSDetData[pQue->wIdx], pInData, sizeof(LUX_BASE_IVSDATA_ST));
pQue->wIdx= (pQue->wIdx+ 1) % LUX_BASE_QUE_MAXSIZE;
Thread_Mutex_UnLock(&g_ivs_que_mux);
return 0;
}
/**
* @description: 消息出队
* @param [in] pQue 队列
* @param [out] pOutData 出队数据
* @return 0 成功,非零失败
*/
int PopQueue(LUX_BASE_IVSQUE_ST *pQue, LUX_BASE_IVSDATA_ST *pOutData)
{
if(NULL == pQue)
{
printf("%s:%d Point NULL!\n", __func__, __LINE__);
return BASE_COMM_ERR;
}
/*判空*/
if(pQue->rIdx== pQue->wIdx)
{
printf("%s:%d Queue is empty !\n", __func__, __LINE__);
return 0;
}
Thread_Mutex_Lock(&g_ivs_que_mux);
memcpy(pOutData, &pQue->IVSDetData[pQue->rIdx], sizeof(LUX_BASE_IVSDATA_ST));
memset(&pQue->IVSDetData[pQue->rIdx], 0, sizeof(LUX_BASE_IVSDATA_ST));
pQue->rIdx= (pQue->rIdx+ 1) % LUX_BASE_QUE_MAXSIZE;
Thread_Mutex_UnLock(&g_ivs_que_mux);
return 0;
}
代码讲解
队列结构体LUX_BASE_IVSQUE_ST
中有三个成员,一个为存放实际数据的结构体,另外两个为写和读的索引。
这里的索引不是地址索引,而是数组的下标索引(当然也可以用一段内存管理,索引用指针,其实都一样)
首先来看消息入队和消息出队的函数对队列的判断——判满、判空
判满
(pQue->wIdx + 1) % LUX_BASE_QUE_MAXSIZE == pQue->rIdx
写入队列后
pQue->wIdx = (pQue->wIdx + 1) % LUX_BASE_QUE_MAXSIZE;
使用数组管理data,索引可以就被理解为数组的下标。写索引应当比读索引快,如果写索引的下一个位置是读索引的位置,那么说明写索引已经绕了一圈回来追上读索引,此时判定为队列已满
判空
pQue->rIdx== pQue->wIdx
出队
pQue->rIdx= (pQue->rIdx+ 1) % LUX_BASE_QUE_MAXSIZE
不难理解,读写索引在一起就是空的。两种情况,一种是刚开始的时候,全局自动初始化为0,此时是在一起的;另一种是读索引追上了写索引,队内是空的没有东西读出来的情况。
入队
检测传入的队列和队列内部情况后开始操作,直接把入队的结构体放到队列结构体的data结构体数组中
入队后写索引往后移动
出队
根据读索引把队列结构体的data结构体数组拷贝到出队结构体中,然后将出队的对接结构体的data结构体数组中对应结构体置0
出队后读索引完后移动
代码隐患讲解
在算法功能长时间运行中,处理消息的队列也在不断进行读写,读索引和写索引不断累加,使用取余可以让读写索引固定在预设范围内,但是读索引和写索引本身不在预设范围内。
因为上面的代码给的索引类型是int型,超过0b~(1 << 31)
这个数字的时候,数据变为负的,那么上面的操作如读写索引的偏移就会出现问题。表现为程序跑挂掉,或者算法触发没送到队列中没上报成功。
这个问题归根究底是C语言基础问题,有符号数和无符号数的问题。
这也是实际项目中,自定义变量类型的原因之一,下面给出海思的自定义类型给大家作为参考
海思的自定义变量类型
/******************************************************************************
Copyright (C), 2001-2011, Hisilicon Tech. Co., Ltd.
******************************************************************************
File Name : hi_type.h
Version : Initial Draft
Author : Hisilicon multimedia software group
Created : 2005/4/23
Last Modified :
Description : The common data type defination
Function List :
History :
1.Date : 2008/06/28
Author : c42025
Modification: modified definition for HI_S8
2.Date : 2008/10/31
Author : z44949
Modification: Translate the chinese comment
3.Date : 2010/11/03
Author : z44949
Modification: Remove some unnecessary typedef
4.Date : 2011/01/05
Author : p00123320
Modification: Modify definition of HI_VOID, avoid C++ compiler warning.
******************************************************************************/
#ifndef __HI_TYPE_H__
#define __HI_TYPE_H__
#ifdef __cplusplus
#if __cplusplus
extern "C"{
#endif
#endif /* __cplusplus */
/*----------------------------------------------*
* The common data type, will be used in the whole project.*
*----------------------------------------------*/
typedef unsigned char HI_U8;
typedef unsigned short HI_U16;
typedef unsigned int HI_U32;
typedef signed char HI_S8;
typedef short HI_S16;
typedef int HI_S32;
/*----------------------------------------------*
* The fixed-point data type, used to represent float data in hardware calculations.*
*----------------------------------------------*/
/*--u8bit---------------------------------------*/
typedef unsigned char HI_U0Q8;
typedef unsigned char HI_U1Q7;
typedef unsigned char HI_U5Q3;
/*--u16bit---------------------------------------*/
typedef unsigned short HI_U0Q16;
typedef unsigned short HI_U4Q12;
typedef unsigned short HI_U6Q10;
typedef unsigned short HI_U8Q8;
typedef unsigned short HI_U12Q4;
typedef unsigned short HI_U14Q2;
/*--s16bit---------------------------------------*/
typedef short HI_S9Q7;
typedef short HI_S14Q2;
typedef short HI_S1Q15;
/*--u32bit---------------------------------------*/
typedef unsigned int HI_U22Q10;
typedef unsigned int HI_U25Q7;
/*--s32bit---------------------------------------*/
typedef int HI_S25Q7;
typedef int HI_S16Q16;
/*----------------------------------------------*
* The fixed-point data type combine with FLAG bits.*
*----------------------------------------------*/
/*8bits unsigned integer,4bits decimal fraction,4bits flag bits*/
typedef unsigned short HI_U8Q4F4;
/*float*/
typedef float HI_FLOAT;
/*double*/
typedef double HI_DOUBLE;
#ifndef _M_IX86
typedef unsigned long long HI_U64;
typedef long long HI_S64;
#else
typedef __int64 HI_U64;
typedef __int64 HI_S64;
#endif
typedef char HI_CHAR;
#define HI_VOID void
/*----------------------------------------------*
* const defination *
*----------------------------------------------*/
typedef enum {
HI_FALSE = 0,
HI_TRUE = 1,
} HI_BOOL;
#ifndef NULL
#define NULL 0L
#endif
#define HI_NULL 0L
#define HI_SUCCESS 0
#define HI_FAILURE (-1)
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */
#endif /* __HI_TYPE_H__ */