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);
}
 

目录
相关文章
|
4月前
|
Java API C++
【C++ 与Qt 线程】C++ std::thread 与Qt qthread多线程混合编程
【C++ 与Qt 线程】C++ std::thread 与Qt qthread多线程混合编程
190 1
|
4月前
|
安全 Java Unix
【C++ 包裹类 std::thread】探索C++11 std::thread:如何使用它来创建、销毁和管理线程
【C++ 包裹类 std::thread】探索C++11 std::thread:如何使用它来创建、销毁和管理线程
169 0
|
12月前
|
JavaScript
说说你对slot的理解?slot使用场景有哪些?
说说你对slot的理解?slot使用场景有哪些?
131 1
|
C++
boost之signal的使用
boost是C++的一个扩展库,被称为C++准标准库,里面的组件很丰富,并且引用方便,85%的组件只需要引用头文件即可使用。在嵌入式系统也可以很方便的使用,这里介绍一下signal的使用,有点类似Qt里的信号槽。 可以接收静态函数、类成员函数、labmda表达式。 下面这个是使用signal封装的一个事件注册处理模板,使用起来还是很方便的。
118 0
|
C++
C/C++ Qt QThread 线程组件应用
QThread库是QT中提供的跨平台多线程实现方案,使用时需要继承QThread这个基类,并重写实现内部的Run方法,由于该库是基本库,默认依赖于`QtCore.dll`这个基础模块,在使用时无需引入其他模块.
229 0
|
Python
may have been in progress in another thread when fork() was called.
may have been in progress in another thread when fork() was called.
135 0
may have been in progress in another thread when fork() was called.
多线程wait,notify,synchronzied以及lock ,await,signal的用法
  今天翻开以前的笔记练了下基本多的多线程。synchronzied,notify,wait的用法,主要用flg下标去控制wait package classForm; public class ThreadDemo4 { public s...
1166 0