平时的项目程序中,经常需要处理多个串口和网络发送过来的数据,而且数据量还比较大,9600的波特率每秒钟至少1000个字节的数据需要处理并反映到界面上,一开始直接和UI主线程同一个线程,在x86的机器上跑还没问题,毕竟X86的机器最少主频也不会低于1.6G,但是如果数据量再更大或者到了ARM上跑,直接UI卡住不动,想到的解决办法就是用多线程,一个线程负责收数据,一个线程负责处理数据,当协议一样的时候,如果需要将数据解析从串口改为网络端口监听的数据,以前的办法是重新写一个tcp通信进行处理,这个并不是非常合理的办法,毕竟解析协议是一样的,所以自己总结了一个通用的数据处理思路:各种数据接收后排队的形式存入一个全局变量,单独开辟一个线程从这个全局变量中读取第一个数据,处理完则移除第一个数据,Qt中的链表直接提供了一个takeFirst函数,用起来非常爽!用while循环读取,在读取的时候加锁,这样的话就不会冲突了。
雏形:
全局变量文件:
复制代码
#ifndef APP_H
#define APP_H
#include "qstring.h"
#include "qstringlist.h"
class App
{
public:
static QStringList list;
};
#endif // APP_H
复制代码
#include "app.h"
QStringList App::list=QStringList();
独立处理数据线程:
复制代码
#ifndef TEST_H
#define TEST_H
#include "qthread.h"
#include "qmutex.h"
class Thread : public QThread
{
Q_OBJECT
public:
Thread();
~Thread();
void stop();
protected:
void run();
private:
QMutex mutex;
volatile bool stopped;
signals:
void readOne(QString txt);
};
#endif // TEST_H
复制代码
#include "thread.h"
#include "app.h"
Thread::Thread()
{
stopped=false;
}
Thread::~Thread()
{
}
void Thread::stop()
{
stopped=true;
}
void Thread::run()
{
while(!stopped){
mutex.lock();
if (App::list.count()>0){
QString txt=App::list.takeFirst();
emit readOne(txt);
}
mutex.unlock();
msleep(1);//不加这句CPU占用率高达50%
}
stopped=false;
}
主界面:
复制代码
#ifndef WIDGET_H
#define WIDGET_H
#include
#include "thread.h"
#include "qtimer.h"
namespace Ui {
class frmMain;
}
class frmMain : public QWidget
{
Q_OBJECT
public:
explicit frmMain(QWidget *parent = 0);
~frmMain();
private slots:
void writeOne();
void readOne(QString txt);
void on_btnAppend_clicked();
void on_btnThread_clicked();
void on_btnTimer_clicked();
private:
Ui::frmMain *ui;
QTimer *timer;
Thread *thread;
};
#endif // WIDGET_H
复制代码
#include "frmmain.h"
#include "ui_frmmain.h"
#include "app.h"
#include "qdatetime.h"
#include "qdesktopwidget.h"
#define _TIME_ qPrintable (QTime::currentTime().toString("now : hh:mm:ss:zzz"))
frmMain::frmMain(QWidget *parent) :
QWidget(parent),
ui(new Ui::frmMain)
{
ui->setupUi(this);
this->showMaximized();
timer=new QTimer(this);
timer->setInterval(50);
connect(timer,SIGNAL(timeout()),this,SLOT(writeOne()));
thread=new Thread;
connect(thread,SIGNAL(readOne(QString)),this,SLOT(readOne(QString)));
}
frmMain::~frmMain()
{
delete ui;
}
void frmMain::writeOne()
{
App::list.append(_TIME_);
}
void frmMain::readOne(QString txt)
{
ui->txtOut->append(txt);
}
void frmMain::on_btnAppend_clicked()
{
App::list.append(ui->txtIn->text());
}
void frmMain::on_btnThread_clicked()
{
if (ui->btnThread->text()=="start thread"){
thread->start();
ui->btnThread->setText("stop thread");
ui->txtOut->append("start thread ok");
}else{
thread->stop();
ui->btnThread->setText("start thread");
ui->txtOut->append("stop thread ok");
}
}
void frmMain::on_btnTimer_clicked()
{
if (ui->btnTimer->text()=="start timer"){
timer->start();
ui->btnTimer->setText("stop timer");
ui->txtOut->append("start timer ok");
}else{
timer->stop();
ui->btnTimer->setText("start timer");
ui->txtOut->append("stop timer ok");
}
}
为了模拟大量数据,我这里开了50毫秒的定时器定时产生当前时间字符串的数据存入全局变量,然后放置了几个按钮用于手动添加字符串和开始停止线程及定时器。
欢迎提出批评建议以及指点!谢谢!
另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。