SeetaFaceQt:Qt多线程
为什么要做多线程,说个最简单的道理就是我们不希望在软件处理数据的时候界面处于无法响应的假死状态。有些处理是灰常花时间的,如果把这样的处理放到主线程中执行,就会导致软件一条路走到底,要等到处理完才能接收响应其他操作,这时候就会导致界面假死。
Qt提供了一个方法用于在提醒软件先处理下未处理的事情,QApplication::processEvents(),所以,如果在主线程中处理一些耗时操作,可以试下频繁的调用QApplication::processEvents()来提醒系统去处理那些未处理的事。但是这个方法毕竟事不靠谱的,某些情况还勉强可以处理,如果耗时操作封装在一个函数接口里,而我们只能去调用它的时候,这个方法就灰常无效,最终还是得用上多线程的方法。
1、QThread
这种方法跟C++的Thread操作时类似的,定义一个类继承QThread,然后重写run()方法,操作几乎是跟C++的Thread一样的。不过这种方法我现在用的很少,几乎就没怎么使用了。
所以重点还是说下第二种方法。
2、moveToThread
这种方法真的是很方便的了。操作就是先定义一个继承QObject的类,然后通过QObject的moveToThread()函数将对象移到一个子线程中就可以实现多线程了。这么简单的方法当然是要跟Qt的信号与槽来配合使用啦。
首先,我们定义一个处理子类继承QObject,然后将我们要放到子线程中执行的操作写到一个槽函数中,然后在主线程中需要处理数据的时候就先将数据传入后通过发射信号令其执行,然后子线程执行完之后发送一个信号通知主线程做出响应即可。
class SeetaFaceThread : public QObject
{
Q_OBJECT
public:
SeetaFaceThread(QObject *parent);
~SeetaFaceThread();
public slots:
void detectFaceSlot(void);
}
这样定义好一个线程类即可了,然后使用的时候,就实例化一个SeetaFaceThread对象和一个QThread对象,然后调用moveToThread()函数将其移到该子线程中,然后通过信号槽函数启动线程,这个做法很多教程都说的很仔细了。然后我想说的是另一种做法,把QThread对象在QObject的子类中实现,这样,在实现QObject的子类的时候就不再需要再去定义一个QThread,使得QObject的子类实现起来更加简单,而不需要考虑线程的结束问题。这个时候需要在QObject的子类中实例化一个QThread的对象,并将QObject的子类moveToThread(),然后需要析构函数里将线程释放。具体的实现如下,在头文件里声明一个QThread类:
QThread *m_pThread;
然后在源文件的构造函数里实例化对象:
m_pThread = new QThread(this);
m_pThread->start();
this->moveToThread(m_pThread);
在析构函数里释放线程:
m_pThread->quit();
m_pThread->wait();
delete m_pThread;
m_pThread = NULL;
这样在构造QObject的子类的时候其实就已经将子类移到子线程中了,而且,在释放内存的时候也会停止子线程并回收资源。然后在使用的时候,直接对QObject的子类进行实例化,然后记得要构造一些信号,传递会主线程,好让主线程知道处理的进度:
m_pSeetaFaceThread = new SeetaFaceThread(this);
connect(m_pSeetaFaceThread,
SIGNAL(faceDetectedFinishedSig(bool)),
this,
SLOT(faceDetectedFinishedSlot(bool)));
connect(m_pSeetaFaceThread,
SIGNAL(faceRecognizerFinishedSig(QStringList)),
this,
SLOT(faceRecognizerFinishedSlot(QStringList)));
connect(m_pSeetaFaceThread,
SIGNAL(extractingInforSig(QString)),
this,
SLOT(extractingInforSlot(QString)));
上面我在子类里定义了三个信号,主要是要通知主线程处理的结果或者一些处理信息。
然后什么时候或者怎么启动线程呢。一般设定一个信号连接要进行处理的槽函数,同时,要进行处理,应该要让子类得到处理的数据吧,一般时可以用信号槽来传递一些变量的,但是这里不太推荐,因为有些数据其实时复杂变量,信号槽有时候时不起作用的,所以,我一般是在子类里添加一些共有成员方法用来传递数据的,传递数据之后使用QTimer::singleShot()函数来作为信号源,并传递给对应槽函数。QTimer::singleShot()函数的原型有几个,主要用的是下面这个:
static void singleShot(int msec, const QObject *receiver, const char *member);
第一个变量是毫秒时间,一般设置为0就是马上传递信号,后面两位是接收器和槽函数,也就是QObject的子类和对应的槽函数。用法类似这样:
m_pSeetaFaceThread->setFileInfoList(filelist);
QTimer::singleShot(0, m_pSeetaFaceThread, SLOT(extractFeaturesSlot(void)));
这里掐掉一些东西后,固定的套路使用如下:
seetafacethread.h:
#ifndef SEETAFACETHREAD_H
#define SEETAFACETHREAD_H
#include <QObject>
class SeetaFaceThread : public QObject
{
Q_OBJECT
public:
SeetaFaceThread(QObject *parent);
~SeetaFaceThread();
signals:
void faceDetectedFinishedSig(bool);
void faceRecognizerFinishedSig(QStringList);
void extractingInforSig(QString);
public slots:
void detectFaceSlot(void);
void alignmentFaceSlot(void);
void extractFeaturesSlot(void);
void recognizerFaceSlot(void);
private:
QThread *m_pThread;
};
#endif // SEETAFACETHREAD_H
seetafacethread.cpp:
#include "seetafacethread.h"
#include <QThread>
SeetaFaceThread::SeetaFaceThread(QObject *parent)
: QObject(parent)
{
m_pThread = new QThread(this);
m_pThread->start();
this->moveToThread(m_pThread);
}
SeetaFaceThread::~SeetaFaceThread()
{
m_pThread->quit();
m_pThread->wait();
delete m_pThread;
m_pThread = NULL;
}
void SeetaFaceThread::detectFaceSlot(void)
{
//一些处理
//处理完成
emit faceDetectedFinishedSig(true);
}
void SeetaFaceThread::alignmentFaceSlot(void)
{
//一些处理
//处理完成
emit faceDetectedFinishedSig(true);
}
void SeetaFaceThread::extractFeaturesSlot(void)
{
//一些处理
//处理完成
emit extractingInforSig(QString::fromLocal8Bit("完成全部特征提取"));
emit extractingInforSig(QString::fromLocal8Bit(""));
}
void SeetaFaceThread::recognizerFaceSlot(void)
{
//一些处理
//处理完成
emit faceRecognizerFinishedSig(strList);
}
然后在需要处理数据的地方调用QTimer::singleShot()函数来执行即可。
Qt多线程还有另外两种做法:继承QRunnable和使用QtConcurrent::run,这个还是可以参考这篇博客的,但是,这两种方法,应该说QtConcurrent::run会有吸引力一些,查了一下,Qt助手的解释是:“The Qt Concurrent module extends the basic threading support found in Qt Core module and simplifies the development of code that can be executed in parallel on all available CPU cores.”也就是说,QtConcurrent扩展了Qt Core中的线程操作,简化了可在所有可用CPU内核上并行执行的代码开发。后面在对它进行深入研究吧。
你站在桥上看风景,
看风景的人在楼上看你。
明月装饰了你的窗子,
你装饰了别人的梦。
--卞之琳 《断章》
SeetaFaceQt:Qt多线程的更多相关文章
- Qt 多线程和网络编程学习
一,Qt多线程类学习 QThread类,开始一个新的线程就是开始执行重新实现QThread::run(),run()是默认现实调用exec(),QThread::start()开始线程的执行,run( ...
- [转] Qt 多线程学习
Qt 多线程学习 转自:http://www.cnblogs.com/IT-BOY/p/3544220.html 最近的项目上用到了关于多线程的知识,自己也比较感兴趣,所以就拿了那本<C++ G ...
- QT多线程笔记
1.QT多线程涉及到主线程和子线程之间交互大量数据的时候,使用QThread并不方便,因为run()函数本身不能接受任何参数,因此只能通过信号和槽的交互来获取数据,如果只是单方面简单交互数据还过得去, ...
- Qt多线程-总结QThread-QThreadPool-QtConcurrent
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Qt多线程-总结QThread-QThreadPool-QtConcurrent 本文 ...
- Qt多线程-QtConcurrent并行运算高级API
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Qt多线程-QtConcurrent并行运算高级API 本文地址:http://tec ...
- Qt多线程-QThreadPool线程池与QRunnable
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Qt多线程-QThreadPool线程池与QRunnable 本文地址:https:/ ...
- Qt多线程-QThread
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Qt多线程-QThread 本文地址:http://techieliang.com/2 ...
- Qt 多线程同步与通信
Qt 多线程同步与通信 1 多线程同步 Qt提供了以下几个类来完成这一点:QMutex.QMutexLocker.QSemphore.QWaitCondition. 当然可能还包含QReadWrite ...
- 【QT】 Qt多线程的“那些事”
目录 一.前言 二.QThread源码浅析 2.1 QThread类的定义源码 2.2 QThread::start()源码 2.3 QThreadPrivate::start()源码 2.4 QTh ...
随机推荐
- R 《回归分析与线性统计模型》page121,4.4
rm(list = ls()) A = read.xlsx("xiti_4.xlsx",sheet = 4) names(A) = c("ord"," ...
- 123.ModelForm的使用
ModelForm 在我们的实例中,需要通过models.py中定义相关的模型字段,之后在forms.py中同样需要定义每个字段进行相应的验证,这样的话,我们会需要重复定义,这样的话,就相对比较麻烦, ...
- IntelliJ IDEA使用技巧—使用EasyCode插件一键生成代码04期
在现如今的软件开发过程中,软件开发人员将很多的精力放在重复的编码中.特别是流行的MVC架构模式下,项目各个层次的功能更加独立,这也间接的造成了代码的相似度更高.因此需要寻找一种可以减少软件开发人员重复 ...
- 011、Java中将范围大的数据类型变为范围小的数据类型
01.代码如下 package TIANPAN; /** * 此处为文档注释 * * @author 田攀 微信382477247 */ public class TestDemo { public ...
- 吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons):glyphicon glyphicon-minus
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name ...
- c++程序—选择结构
if(判断条件){执行语句} #include<iostream> using namespace std; #include<string> int main() { ; c ...
- Ican协议建立连接我的感悟
有一个情形我突然之间想明白了. 注意下面情形: 假设节点A与节点B已经 正常的建立了连接,并且进行了通讯. 假设 节点B收到了 节点A 的 &q ...
- css快速浏览
meta <meta charset="utf-8" /> <meta name="keywords" content="key1, ...
- JavaWeb高级编程(下篇)
Java标准标签库 JSP标签语法中包含一些简写可以帮助轻松编写JSP.这些简写中第一个就是taglib指令. <%@ taglib prefix="c" uri=" ...
- 033-PHP对一个数组先奇后偶,然后再进行从大到小排序
<?php function Compare($str1, $str2) { if (($str1 % 2 == 0) && ($str2 %2 == 0)) { if ($st ...