QThread与SLOT

简介:
众所周知的,Qt的一个核心的消息机制是信号与槽。当用户点击了某个按钮执行某一个非常庞大要执行很久才成完成的操作时,如果我们没有用线程,那么所有的消息循环全部都在app.exec()中完成。
app.exec()就是一个很大的循环函数,它的功能就是遍历所有控制,看有没有消息要处理。如果有,则执行。只有等执行完成才能进行下一个操作。如果一个操作耗了大量的时间,那么别的事件都没法做了,包括界面刷新、鼠标事件等。

为了解决这个问题,我们必须得用线程来做。将大工作量的活交给次线程去作,主线程(app.exe())不会阻塞继续作界面上的工作。

举个例子:BackgroundWorker是次线程类,用于做一个复杂的运行(我们假设它很复杂)
backgroundworker.h


#ifndef BACKGROUNDWORKER_H
#define BACKGROUNDWORKER_H
 
#include <QThread>
 
class BackgroundWorker : public QObject
{
    Q_OBJECT
public:
    BackgroundWorker();
    ~BackgroundWorker();
 
signals:
    void updateResultSignal(double area);
 
public slots:
    void calculateSlot(double radio);
 
private:
    QThread thread;
};
 
#endif // BACKGROUNDWORKER_H

backgroundworker.cpp:  


#include "backgroundworker.h"
#include <qmath.h>
 
BackgroundWorker::BackgroundWorker()
{
    moveToThread(&thread);
    thread.start();
 
    // TODO other initialize
}
 
BackgroundWorker::~BackgroundWorker()
{
    thread.quit();
    thread.wait();  // wait the thread quit normally
}
 
void BackgroundWorker::calculateSlot(double radio)
{
    double area = 0.0;
    area = qPow(radio, 2) * M_PI;
    sleep(2);  // OH! assume that it is a big work cost 2 seconds to finish it.
 
    emit updateResultSignal(area);
}

注意看构造函数哦!moveToThread(&thread)就是将this对象的信号与槽机制同主线程转交给thread线程去处理。然后就thread.start()启动线程。
在释构函数中,一定要先停线程quit()并等待wait()其正常退出其消息循环,否则退出就会出报线程未停止的异常。

BackgroundWorker::calculateSlot()为计算圆面积的函数。我们假设它的计算量很大,需要花上2秒钟才能完成。主线程在接受到周户的操作时,发送信号给BackgroundWorker,发送信号后主线程就继续处理其它事件去了。由于主线程与BackgroundWorker不是同一个线程,那么消息则是通过消息列队传到BackgroundWorker的,当处理这个BackgroundWorker消息循环的thread线程接收到消息队列里的消息后,会调用calculateSlot()槽进行计算。在完成计算后,再通过发送updateResultSignal()信号将结果返回给主线程,同样是通过消息队列的方式。

其它需要说明的:
(1)如果不同线程间信号发送中的参数有自定义的数据类型,那么就必须先注册到Qt内部的类型管理器中后才能在connect()中使用。


qRegisterMetaType<MyType>("MyType");
 

(2)在次线程中,要不处理GUI相关的内容,包括弹出消息对话框。因为主线程主要负责GUI图像处理操作。如果线程也要插一手,那么可能就会引起冲突了。这样很不安全。
(3)在次线程中,不要使用eventFilter(),这也是不安全的。

(4)不一定非要在类中包含一个QThread,也可以在外面定义一个QThread对象,并把多个对象moveToThread()到同一个线程去处理。
(5)默认情况下,一个对象是由哪个线程实例化的,那么它的消息机制就是由哪个线程来处理。


写一个ExecutableObject类,让所有继承该类的派生类都有独立的消息处理线程。
executableobject.h文件: 


#ifndef EXECUTABLEOBJECT_H
#define EXECUTABLEOBJECT_H
 
#include <QObject>
#include <QThread>
 
class ExecutableObject : public QObject
{
    Q_OBJECT
public:
    explicit ExecutableObject(QObject *parent = 0);
    ~ExecutableObject();
 
private:
    QThread thread;
};
 
#endif // EXECUTABLEOBJECT_H

executableobject.cpp文件:  


#include "executableobject.h"
 
ExecutableObject::ExecutableObject(QObject *parent) :
    QObject(parent)
{
    moveToThread(&thread);
    thread.start();
}
 
ExecutableObject::~ExecutableObject()
{
    thread.quit();
    thread.wait();
}

前面的BackgroundWorker可以精简成: 




#ifndef BACKGROUNDWORKER_H
#define BACKGROUNDWORKER_H
 
#include <QThread>
#include "executableobject.h"
 
class BackgroundWorker : public ExecutableObject
{
    Q_OBJECT
public:
    BackgroundWorker() {}
 
signals:
    void updateResultSignal(double area);
 
public slots:
    void calculateSlot(double radio);
};
 
#endif // BACKGROUNDWORKER_H
 



?

1
2
3
4
5
6
7
8
9
10
11
 
#include "backgroundworker.h"
#include <qmath.h>
 
void BackgroundWorker::calculateSlot(double radio)
{
    double area = 0.0;
    area = qPow(radio, 2) * M_PI;
    sleep(2);  // OH! assume that it is a big work cost 2 seconds to finish it.
 
    emit updateResultSignal(area);
}
 

目录
相关文章
|
弹性计算 关系型数据库 数据建模
Docker部署openclinica
OpenClinica是全球第一款开源临床试验(简称EDC)及临床数据管理(简称CDM)软件,传统部署可参考https://docs.openclinica.com/ 官网,这是为了方便采用Docker部署,https://hub.docker.com上有对应的镜像可以使用
1228 0
|
数据采集 Linux 数据处理
深入了解Linux命令:rev
`rev`命令在Linux中反转文本字符顺序,用于数据预处理和分析。它可以改变每行字符的排列,例如`echo &quot;Hello, World!&quot; | rev`输出`!dlroW ,olleH`。常用参数包括显示版本信息的`-V`。结合其他命令如`cat`,可处理文件内容。注意行格式和性能影响,适用于小到中型数据处理。
|
弹性计算 Ubuntu Linux
Ubuntu 镜像-阿里云
Ubuntu 镜像-阿里云
682 1
|
机器学习/深度学习 人工智能 运维
智能化运维:AI在故障预测中的应用
【6月更文挑战第8天】随着人工智能技术的飞速发展,其在IT运维领域的应用也日益广泛。本文将探讨AI技术如何助力运维团队实现故障的智能预测,提高系统稳定性和业务连续性。
|
运维 自然语言处理 Kubernetes
如何在 ACK 中使用 MSE Ingress
本文将为大家分享一下 Ingress 标准 和 实现的趋势,介绍一下 MSE Ingress 在这个趋势下的优势和实践,为大家做关键入口选择多一些参考。
738 103
如何在 ACK 中使用 MSE Ingress
|
分布式计算 资源调度 Hadoop
Hadoop中的MapReduce概述、优缺点、核心思想、编程规范、进程、官方WordCount源码、提交到集群测试、常用数据序列化类型、WordCount案例实操
优点:易于编程、良好的扩展性、高容错性、适合PB级以上海量数据的离线处理、缺点:不擅长实时计算、不擅长流式计算、不擅长DAG(有向无环图)计算、MapReduce核心功能是将`用户编写的业务逻辑代码`和`自带默认组件`整合成一个完整的分布式运算程序,并发运行在一个Hadoop集群上。MapReduce是一个分布式运算程序的编程框架,是用户开发“基于Hadoop的数据分析应用”的核心框架。(1)分布式的运算程序往往需要分成至少2个阶段。(2)第一个阶段的MapTask并发实例,完全并行运行,互不相干。(3)第
769 1
Hadoop中的MapReduce概述、优缺点、核心思想、编程规范、进程、官方WordCount源码、提交到集群测试、常用数据序列化类型、WordCount案例实操
|
存储 数据挖掘 测试技术
什么是数据智能,为什么它很重要?
数据是当今世界上最有价值的资源之一。它是本世纪的货币,知道如何管理和使用数据的公司发现它很容易增长。
523 0
什么是数据智能,为什么它很重要?
|
弹性计算 安全 Ubuntu
保姆级教程!在ECS上部署高版本Wordpress以及运行环境!
阿里云控制台提供了安装运行wordpress的简单教程但默认安装的版本较低且已失去安全支持。本文希望提供一种简单的方式安装高版本的wordpress。
保姆级教程!在ECS上部署高版本Wordpress以及运行环境!
|
传感器 数据采集 存储
物联网平台如何支持设备的多样化接入
我们常说,物联网平台的使命就是将物理世界映射到数字世界,而对于具体的一个物联网设备而言,要完成数字化的前提,首先是必须要能够通过某种方式直接或者间接的“接入”到云端。从“接入”这个视角去看,传统的互联网场景下,往往以app、web接入为主,app和浏览器在接入上的实现一般都是比较标准的,相应的提供接入服务的云端实现也就比较标准。而在物联网世界中,情况就大不相同了,千奇百怪的设备,特点各异的应用场景,组合出非常多样化的接入需求,因而对于物联网的接入层的实现也就提出了多样化的挑战。
2820 1
|
数据采集 数据可视化 BI
一份可视化特征图的代码
本文给大家分享一份我用的特征图可视化代码。 欢迎关注公众号CV技术指南,专注于计算机视觉的技术总结、最新技术跟踪、最新论文解读、各种技术教程、CV招聘信息发布等。关注公众号可邀请加入免费版的知识星球和技术交流群。
一份可视化特征图的代码