QThread与SLOT

2013-04-14  来源:本站原创  分类:Qt  人气:13 

众所周知的,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
#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);
}
相关文章
  • QThread与SLOT 2013-04-14

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

  • QThread介绍(译) 2014-09-09

    QThread类提供了独立于平台的处理线程类. 在程序中,一个QThread对象处理一个线程.QThread通过start方法创建一个新线程,新线程调用run方法(所以在程序中看到的是run方法在新线程中运行.是否只有run方法运行在新线程中?).默认情况下,run方法通过调用exec方法启动事件循环,并在线程内运行Qt 事件循环.当退出run方法将会终止这个新线程. 你可以通过QObject::moveToThread方法将worker对象移动到某个线程中. class Worker : pu

  • Qt QThread 2015-05-12

    多线程考虑的几件事: 实例变量属于哪个线程?(不是在子线程中定义的,都是主线程,假设只有俩线程,多了以此类推). 在哪个线程定义的实例变量的函数都是在该线程中执行的. 连接线程的事件(信号与槽),属于跨线程通讯,还是本线程通讯. 可以通过moveToThread(QThread)来改变该变量的所属范围(即该实例变量移到了这个线程) 主要把握实例变量的所属问题,然后考虑多线程调度是否会访问同一变量,是否需要加锁.加锁后是否因为不当代码导致了死锁问题. 线程应该是一个重量级的东西,应该考虑成类似ma

  • Oracle block itl slot of the flag 2011-04-11

    dump the Oracle block, you can see the groove of things, contains the slot number of things (ITL), XID, UBA, FLAG, LCK, SCN. This paper discusses the FLAG tag of the rules, which FLAG in the block occupied by a byte size. We know FLAG tag representat

  • [Transfer] SQL Server Tips: text.ntext or image node page (1: XX), 4 slot solution that does not exist 2011-08-16

    SQL SERVER query the database will appear similar to the following tips: Microsoft OLE DB Provider for SQL Server (0x80004005) [Microsoft] [ODBC SQL Server Driver] [SQL Server] text, ntext, or image node page (1:220), slot 14 does not exist. [Microso

  • Qt 线程基础(QThread.QtConcurrent.QThreadPool等) 2012-11-08

    使用线程 基本上有种使用线程的场合: 通过利用处理器的多个核使处理速度更快. 为保持GUI线程或其他高实时性线程的响应,将耗时的操作或阻塞的调用移到其他线程. 何时使用其他技术替代线程 开发人员使用线程时需要非常小心.启动线程是很容易的,但确保所有共享数据保持一致很难.遇到问题往往很难解决,这是由于在一段时间内它可能只出现一次或只在特定的硬件配置下出现.在创建线程来解决某些问题之前,应该考虑一些替代的技术 : 替代技术 注解 QEventLoop::processEvents() 在一个耗时的计

  • Qt 线程基础(QThread.QtConcurrent等) 2012-11-10

    昨晚看Qt的Manual,突然发现下一个版本的Qt中(Qt4.7.4.Qt4.8等)增加了一个特赞的介绍多线程的文章 : Thread Basics 注意: 该链接以后会失效,但是 到时候你直接看Qt自带Manual就行了 本文不是严格的翻译 dbzhang800 2011.06.18 使用线程 基本上有种使用线程的场合: 通过利用处理器的多个核使处理速度更快. 为保持GUI线程或其他高实时性线程的响应,将耗时的操作或阻塞的调用移到其他线程. 何时使用其他技术替代线程 开发人员使用线程时需要非常

  • Qt 中的多线程(二) 2015-05-03

    可重入与线程安全 在Qt文档中,术语"可重入"与"线程安全"被用来说明一个函数如何用于多线程程序.假如一个类的任何函数在此类的多个不同的实例上,可以被多个线程同时调用,那么这个类被称为是"可重入"的.假如不同的线程作用在同一个实例上仍可以正常工作,那么称之为"线程安全"的. 大多数c++类天生就是可重入的,因为它们典型地仅仅引用成员数据.任何线程可以在类的一个实例上调用这样的成员函数,只要没有别的线程在同一个实例上调用这个成员

  • Qt中的多线程编程 2010-08-18

    Qt中的多线程编程 级 别: 初级 续欣 ([email protected]), 2004 年 4 月 01 日 Qt 作为一种基于 C++ 的跨平台 GUI 系统,能够提供给用户构造图形用户界面的强大功能.为了满足用户构造复杂图形界面系统的需求,Qt 提供了丰富的多线程编程支持. Qt 作为一种基于 C++ 的跨平台 GUI 系统,能够提供给用户构造图形用户界面的强大功能.为了满足用户构造复杂图形界面系统的需求,Qt 提供了丰富的多线程编程支持.从 2.2 版本开始,Qt 主要从下面三个方

  • 我的专属QQ (三) 附源码 2012-02-14

    要源码的朋友太多了,满眼的邮箱地址,我很头疼.鉴于现在CSDN首页的Qt应用大赛正在火热进行中,我干脆把源码奉献出来,给大家参考一下好了.不过,这不是我一个人的劳动成果,我一直认为技术领域的最高境界是分享,所以希望得到你的尊重. 有什么好的意见和建议欢迎你提,但是请注意语气.我写博客的目的有两个,一是记录,二是分享.我记录我的学习历程,分享给大家.我不是神,我想神也不能精通各个技术领域,不是最好的方案你就冷嘲热讽,于情于理都不太合适吧.我这又不是出书,你掏腰包买了看了觉得不好,骂几句才痛快.我自

  • 阅读QtCreator--Concurrent预备知识 2012-07-19

    在QtCreator当中用到了不少的Concurrent(并发),比如编译时,搜索时等.其实在很多场合中都需要用到,一般是CPU去做一项大任务(花费较长时间)时相应用户操作.另一个重要用途就是在当前这个多核,甚至多CPU的年代,并行变成成为一种时尚了,它也确实提高了应用程序的性能.我的电脑是单CPU,2核心4线程,所以相比单应用程序,应该可以将性能提高将近4倍(当然不会是4倍的).我所听过的有很多库是这方面的,比如CUDA,OpenCL,OpenMP.Qt是怎么做的还真不知道,望高手指教.首先来

  • Qt下几个线程函数介绍 2012-11-09

    1.QCoreApplication::processEvents() 2.每个线程可以有它的事件循环,初始线程开始它的事件循环需使用QCoreApplication::exec(),别的线程开始它的事件循环需要用QThread::exec().像QCoreApplication一样,QThreadr提供了exit(int)函数,一个quit() slot. 线程安全的函数QCoreApplication::postEvent(),在任何时候,给任何线程中的任何对象投递一个事件,事件会在那个创建

  • qt线程----部分代码片段 2012-11-09

    一.把视频显示到界面的方法 (1)针对qt4的(视频格式为rgb32) v4l_grab_movie(&v4l_dev); unsigned char *pBuffer= v4l_dev.buffer; QImage image(pBuffer,320,240,QImage::Format_RGB32); QPixmap pixmap; pixmap=pixmap.fromImage(image); label->setPixmap(pixmap); label->setFixedSi

  • Qt线程基础(这个比较完整) 2012-11-09

    线程基础 保谓线程? 线程与并行处理任务息息相关,就像进程一样.那么,线程与进程有什么区别呢?当你在电子表格上进行数据结算的时候,在相同的桌面上可能有一个播放器正在播放你最喜欢的歌曲.这是一个两个进程并行工作的例子:一个进程运行电子表格程序;另一个进程运行一个媒体播放器.这种情况最适合用多任务这个词来描述.进一步观察媒体播放器,你会发现在这个进程内,又存在并行的工作.当媒体播放器向音频驱动发送音乐数据的时候,用户界面上与之相关的信息不断地进行更新.这就是单个进程内的并行线程. 那么,线程的并行性

  • T 线程池 + TCP 实战笔记 实现最终功能 2012-11-09

    很久以前做过ACE + MFC/QT 的中轻量级线程池应用,大概就是利用线程池执行客户机上的运算需求,将结果返回.ACE是跨平台重量级的通信中间件,与常见的应用程序框架需要精心契合,才能不出问题.最近想到既然QT框架本身就已经具有各类功能,何不玩一玩呢,那就开搞!这个实验的代码可以从我的资源内下载. 第一步打算实现的模式,我们需要一个设置为CPU核心数的线程池,这个线程池可以异步接受N个数据生产者传入的数据,均衡的分配处理任务,处理后的数据返回给某1个或者几个消费者.有两种均衡方法.一种是生产者

  • Qt技术应用常见问题解答 2012-11-28

    1.如果在窗体关闭前自行判断是否可关闭 答:重新实现这个窗体的closeEvent()函数,加入判断操作 Quote: void MainWindow::closeEvent(QCloseEvent *event) { if (maybeSave()) { writeSettings(); event->accept(); } else { event->ignore(); } } 2.如何用打开和保存文件对话 答:使用QFileDialog Quote: QString fileName =

  • Qt的多线程编程注意事项 2014-04-01

    QT总的来说是一个易学易用的库, 但是QT的多线程使用确实容易犯错,尤其是结合上异步的网络访问,谁用谁知道.我觉得核心是一句话,QThread要当作线程控制块用,不要以为派生一个QThread的子类,里面的东西都跑在新的线程里了,只有run()里的是这样. 下面这篇文章我觉得讲的很好,深入解析QT的线程用法,文章有点长,但是值得一读. 原文在 http://qt-project.org/wiki/ThreadsEventsQObjects 译文在 http://www.cppblog.com/b

  • Qt线程和定时器[一] 2014-08-14

    新的线程run里面一定要有exec的调用,否则无法接受消息的. class myQThr : public QThread { Q_OBJECT public: myQThr(QObject *in = NULL) :QThread(in) { WrTimer = new QTimer(this); connect(WrTimer, SIGNAL(timeout()), this, SLOT(TimerOutWr1()), Qt::DirectConnection); WrTimer->star

  • QT线程与定时器[二] 2014-08-14

    下面转一个相关说明吧 实例代码1: class MThread :public QThread { public: MThread(); ~MThread(); virtual void run(); void foo(); ... }; POINT 1:QThread类的实例与普通类的实例没什么不同,只是运行着的run()函数会不同 实例代码2: class MDialog :public QDialog { ... MThread *mythread; }; MDialog::MDialog

  • Qt::ConnectionType 解析 2014-08-14

    signal/slot在底层会使用三种方式传递消息.参见QObject::connect()方法: bool QObject::connect ( const QObject * sender, const char * signal, const QObject * receiver, const char * method, Qt::ConnectionType type = Qt::AutoCompatConnection ) 最后一个参数是就是传递消息的方式了,有四个取值: Qt::Di