对qt多线程以及事件投递的理解


用QThread启动线程的良好方法以及理解。

1) 用原始的QThread的started信号触发自定义的slot启动线程,而不是派生QThread的类重载run函数启动线程。
将一个类派生自QObject,然后实现所有的signal/slot,然后通过调用movetothread函数来使他们执行在新的线程里面,而不是每次都要重新派生QThread,并且派生QThread的另外一个不好的地方是只有run函数内部的代码才会执行在新线程里面,相比起来,派生QObject并使用movetothread函数更具有灵活性。

2) 自定义对象moveToThread进线程后,事件循环可以完全在此线程中运行。而它的内存管理应该还属于主线程。
如下例子中(MyObject* myObj)被moveToThread进线程(QThread *thread)。假如对象(MyObject* myObj)有父亲,它不能移动这种关系。在另一个线程(而不是创建它的那个线程)中delete QObject对象是不安全的。除非你可以保证在同一时刻对象不在处理事件。可以用QObject::deleteLater(),它会投递一个DeferredDelete事件,这会被对象线程的事件循环最终选取到。

3)exec的重要性。
主线程开始它的事件循环需要调用QCoreApplication::exec(), 子线程需要用QThread::exec(),功能基本是一样的,当然qt内部肯定是不同的实现。
假如没有事件循环运行,事件不会分发给对象。举例来说,假如你在一个线程中创建了一个QTimer对象,但从没有调用过exec(),那么QTimer就不会发射它的timeout()信号.对deleteLater()也不会工作。(这同样适用于主线程)。

4) 子线程接收事件
a) 如下例子中,子线程并没有执行exec(),确切地说是QThread::exec(),那么其实我也可以把Qtrhead换成Qthread派生类,在run中执行事件循环。但是, 其实用主线程的exec(), 加上moveToThread,加上connect的时候使用Qt::QueuedConnection就可以让slot在子线程中运行,那么在子线程exec也没多大意义了。
b)本例子真正使用的是QCoreApplication::postEvent,和重载QObject类的customEvent的方法。消息一样会在(MyObject* myObj)所在的线程处理。

5) 关于QCoreApplication::postEvent和QCoreApplication::sendEvent
postEvent: 可以给别的线程发送事件。事件会在目的对象所属的线程中运行。这是一个异步接口。
sendEvent: 仅用于同一个线程之间发送事件。目的对象必须与当前线程一样。这是一个同步接口。假如发送给属于另一个线程的对象,会报错:ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread a51f48. Receiver ‘‘ (of type
 ‘MyObject‘) was created in thread a3bf18", file kernel\qcoreapplication.cpp, line 539




以下是结合上述描述的3个文件。可正常编译运行。

-------------------------------------------------------------------------------------------------
maim.cpp
-------------------------------------------------------------------------------------------------

#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include <QObject>
#include <QTimer>
#include "myobject.h"


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    qDebug() << "main:" << (qlonglong)QThread::currentThreadId();

    //! 业务逻辑对象
    MyObject* myObj = new MyObject;
    //! 线程
    QThread *thread = new QThread();
    //! 定时器
    QTimer *timer = new QTimer();

    //! 把业务逻辑对象设置进线程,不要把Qthread放进自己线程,这样的写法不建议。
    myObj->moveToThread(thread);

    //! 线程启动
    thread->start();

    //! 绑定的时候最好设置QueuedConnection。这样就允许在myObj线程执行,否则可能会在主线程执行。
    //! 如果希望不要再子线程执行,用DirectConnection。
    QObject::connect(thread, SIGNAL(started()), myObj, SLOT(Started()), Qt::QueuedConnection);
    QObject::connect(timer, SIGNAL(timeout()), myObj, SLOT(Timeout()), Qt::QueuedConnection);
    //! 定时器启动
    timer->start(1000);

    //! 发送事件
    QCoreApplication::postEvent(myObj, new QEvent(CustomEvent_Login));
    qDebug() << QString("[%1]send the event: %2!")
                .arg((qlonglong)QThread::currentThreadId())
                .arg(CustomEvent_Login);

    //! MyObject::Started/MyObject::Timeout/都会在同一个子线程调用。
    return a.exec();
}




-------------------------------------------------------------------------------------------------





myobject.cpp
-------------------------------------------------------------------------------------------------
#include "myobject.h"
#include <QDebug>
#include <QThread>

MyObject::MyObject()
{
}


void MyObject::Started()
{
    qDebug() << "Started:" << (qlonglong)QThread::currentThreadId() ;
}

void MyObject::Timeout()
{
    qDebug() << "Timeout:" << (qlonglong)QThread::currentThreadId() ;
}

void MyObject::customEvent(QEvent *e)
{
    if (e->type() == CustomEvent_Login) //捕获消息
    {

        qDebug() << QString("[%1]catch the event: %2!")
                       .arg((qlonglong)QThread::currentThreadId())
                       .arg(e->type());
    }
}





-------------------------------------------------------------------------------------------------
myobject.h
-------------------------------------------------------------------------------------------------
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QObject>

#include <QEvent>


const QEvent::Type CustomEvent_Login = (QEvent::Type)5001; //! 建议用5000以上唯一的标识

class MyObject : public QObject
{
    Q_OBJECT
public:
    MyObject();

protected slots:
    void Started();
    void Timeout();

private:
    void customEvent(QEvent *e); //! 重载QObject的续虚函数

};

#endif // MYOBJECT_H
				
时间: 2024-11-11 08:48:47

对qt多线程以及事件投递的理解的相关文章

QT 多线程程序设计(也有不少例子)

QT通过三种形式提供了对线程的支持.它们分别是,一.平台无关的线程类,二.线程安全的事件投递,三.跨线程的信号-槽连接.这使得开发轻巧的多线程Qt程序更为容易,并能充分利用多处理器机器的优势.多线程编程也是一个有用的模式,它用于解决执行较长时间的操作而不至于用户界面失去响应.在Qt的早期版本中,在构建库时有不选择线程支持的选项,从4.0开始,线程总是有效的. 线程类 Qt 包含下面一些线程相关的类:QThread 提供了开始一个新线程的方法QThreadStorage 提供逐线程数据存储QMut

Qt多线程编程总结(一)(所有GUI对象都是线程不安全的)

Qt对线程提供了支持,基本形式有独立于平台的线程类.线程安全方式的事件传递和一个全局Qt库互斥量允许你可以从不同的线程调用Qt方法. 这个文档是提供给那些对多线程编程有丰富的知识和经验的听众的.推荐阅读: Threads Primer: A Guide to Multithreaded Programming Thread Time: The Multithreaded Programming Guide Pthreads Programming: A POSIX Standard for Be

QT开发(三十四)——QT多线程编程

QT开发(三十四)--QT多线程编程 一.QT多线程简介 QT通过三种形式提供了对线程的支持,分别是平台无关的线程类.线程安全的事件投递.跨线程的信号-槽连接. QT中线程类包含如下: QThread 提供了开始一个新线程的方法    QThreadStorage 提供逐线程数据存储    QMutex 提供相互排斥的锁,或互斥量    QMutexLocker 是一个辅助类,自动对 QMutex 加锁与解锁    QReadWriterLock 提供了一个可以同时读操作的锁    QReadL

QT 多线程程序设计【转】

QT通过三种形式提供了对线程的支持.它们分别是,一.平台无关的线程类,二.线程安全的事件投递,三.跨线程的信号-槽连接.这使得开发轻巧的多线程Qt程序更为容易,并能充分利用多处理器机器的优势.多线程编程也是一个有用的模式,它用于解决执行较长时间的操作而不至于用户界面失去响应.在Qt的早期版本中,在构建库时有不选择线程支持的选项,从4.0开始,线程总是有效的. 线程类 Qt 包含下面一些线程相关的类:QThread 提供了开始一个新线程的方法QThreadStorage 提供逐线程数据存储QMut

Qt 多线程程序设计

看到一篇好文章,特地转载下来,很详细很全面,收藏之. 原文地址:  http://blog.21ic.com/user1/1425/archives/2009/64057.html QT 多线程程序设计 QT通过三种形式提供了对线程的支持.它们分别是,一.平台无关的线程类,二.线程安全的事件投递,三.跨线程的信号-槽连接. 这使得开发轻巧的多线程Qt程序更为容易,并能充分利用多处理器机器的优势.多线程编程也是一个有用的模式,它用于解决执行较长时间的操作而不至于用户界面失去响应.在Qt的早期版本中

Qt多线程学习:创建多线程

[为什么要用多线程?] 传统的图形用户界面应用程序都仅仅有一个运行线程,而且一次仅仅运行一个操作.假设用户从用户界面中调用一个比較耗时的操作,当该操作正在运行时,用户界面一般会冻结而不再响应.这个问题能够用事件处理和多线程来解决. [Linux有线程的概念吗?] 传统的UNIX系统也支持线程的概念,但一个进程里仅仅同意有一个线程,这样多线程就是多进程.Linux下的Posix线程(pthreads)是一种轻量级的进程的移植性实现,线程的调度由内核完毕,每一个线程都有自己的编号.假设使用线程,整体

QT多线程[转]

Qt作为一种基于 C++ 的跨平台 GUI 系统,能够提供给用户构造图形用户界面的强大功能.为了满足用户构造复杂图形界面系统的需求,Qt提供了丰富的多线程编程支持.从 2.2 版本开始,Qt主要从下面三个方面对多线程编程提供支持:一.构造了一些基本的与平台无关的线程类:二.提交用户自定义事件的 Thread-safe方式:三.多种线程间同步机制,如信号量,全局锁.这些都给用户提供了极大的方便.不过,在某些情况下,使用定时器机制能够比利用 Qt本身的多线程机制更方便地实现所需要的功能,同时也避免了

Qt自己定义事件实现及子线程向主线程传送事件消息

近期在又一次学习Qt的时候,由于要涉及到子线程与主线程传递消息,所以便琢磨了一下.顺便把有用的记录下来,方便自己以后查询及各位同仁的參考! 特此声明,本篇博文主要讲述有用的,也就是直接说明怎么实现,就不打算陈述一大堆理论啦,只是,还是建议大家去查查对应的理论比較好.这样能对Qt的消息传送机制的理解更加深入. 依据网上大多数人的资料,要实现自己定义消息,须要从QEvent 派生一个自己定义的事件:事实上也能够不须要,仅仅要使用QEvent::Type自己定义一个事件即可了. 在这里,本人把两种实现

QT多线程实例

自定义信号与槽 Qt多线程简单实现 多线程间变量传递 工程结构 主线程类: //export_key.h#ifndef EXPORT_KEY_H#define EXPORT_KEY_H#include "main_widget.h"namespace Ui { class export_key; } class texport_work; class export_key : public QWidget {     Q_OBJECTpublic:    explicit export