一、问题描述
在使用多线程接收并处理数据时,采用了数据驱动的方式进行数据处理。
即在接收到网络数据时,会先将网络数据放入一个QVector容器中,定义一个容器如下:
QVector<QByteArray>queue_RecvDatas;
接收网络数据放入该容器,如下:
QByteArray data=m_data;
queue_RecvDatas.append(data);
同时,新建一个线程,通过不断判断容器是否为空,达到数据驱动处理数据的效果,如下:
void tcp_receiver_thread::run()
{
while(1)
{
if(!queue_RecvDatas.isEmpty())
{
QByteArray data=queue_RecvDatas.first();
qDebug()<<data;
queue_ResultDatas.pop_front();
}
}
}
处理完数据后,将数据移除QVector容器。
随后出现不断的报错,如下报错:
double free or corruption (out)
或者如下报错:
corrupted size vs prev_size
二、问题分析
分析上述报错,可以得知是内存处理时的异常。
经过排查,可以认定出现问题的可能性有两点。
- 处理速度跟不上接收速度时,可能会出现错误。
- 在取值或者移除值时,刚好也在做增加操作,就会出问题。
总之,就是对QVector容器的多个操作起了冲突,导致的软件崩溃。
三、解决方法
为了避免出现多个操作出现冲突,因此需要保证同时对一个容器只有一个操作,笔者又希望保留数据驱动的特点。因此设计如下方法:
首先,全局定义从一个容器,改成两个容器,分别为接收容器和处理容器。再添加一个bool判断,用来保证当处理容器在处理数据时候,接收容器不会给处理容器添加数据,但此时接收容器仍旧在接收网络报文数据。当处理容器为空时,接收容器将累计的网络报文一次性交给处理容器,并将自己清空。
全局定义如下:
QVector<fRecvData>queue_RecvDatas;//接收缓存区数据
QVector<fRecvData>queue_ResultDatas;//处理缓存区数据
bool ifGetNewData;//是否从接收缓存区容器中取数
网络报文接收内容如下:
QByteArray data=m_data;
//将从网络缓存区获取的数据放入接收缓存区
queue_RecvDatas.append(data);
if(ifGetNewData)
{
//当处理缓存区处理完数据,将接收缓存区中的数据放入处理缓存区
queue_ResultDatas.append(queue_RecvDatas);
//并将接收缓存区清空
queue_RecvDatas.clear();
}
处理容器如下:
void tcp_receiver_thread::run()
{
while(1)
{
if(!queue_ResultDatas.isEmpty())
{
ifGetNewData=false;//停止往处理缓存区放入数据
QByteArray data=queue_ResultDatas.first();
qDebug()<<data;
queue_ResultDatas.pop_front();
}else{
//当处理缓存区处理完数据,允许往处理缓存区放入数据
ifGetNewData=true;
}
}
}
如此便可避免对容器的操作冲突导致的崩溃。