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

9 篇文章 0 订阅
   
   
用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()函数。原因是exec()函数在QThread的run()中调用了。
我们这里并没有做一个QThread派生类,在run中调用exec()。因为我不推荐怎么干。原因很简单,并不需要这么干。进一步说明是:qt提供的QThread已经完全满足线程创建的需要。为什么还要自己再画蛇添足呢。
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
  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Qt Creator 多线程读取文件到程序显示 利用QT Creator多任务读取一个文档到程序里 为了防止直接读取文件里的内容太大而发生卡顿,于是多线程读取将更高效的解决这个问题。 效果图如下: 其中pro文件无需改动,默认就好,头文件h里面的内容为 #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MyObj; class MyObj : public QObject { Q_OBJECT public: MyObj(); //新的线程 signals: void toLine(QString line); private slots: void doWork(); }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void appendText(QString); //定义一个槽 private: Ui::MainWindow *ui; QThread *t; MyObj *obj; }; #endif // MAINWINDOW_H 而MAIN主文件的内容为了防止中文乱码做了如下修改: #include "mainwindow.h" #include #include int main(int argc, char *argv[]) { QApplication a(argc, argv); //设置中文字体 防止乱码 a.setFont(QFont("Microsoft Yahei", 9)); //设置中文编码 #if (QT_VERSION <= QT_VERSION_CHECK(5,0,0)) #if _MSC_VER QTextCodec *codec = QTextCodec::codecForName("GBK"); #else QTextCodec *codec = QTextCodec::codecForName("UTF-8"); #endif QTextCodec::setCodecForLocale(codec); QTextCodec::setCodecForCStrings(codec); QTextCodec::setCodecForTr(codec); #else QTextCodec *codec = QTextCodec::codecForName("UTF-8"); QTextCodec::setCodecForLocale(codec); #endif MainWindow w; w.show(); return a.exec(); } 接下来重点来了,源文件CPP里为 #include "mainwindow.h" #include "ui_mainwindow.h" #include #include #include #include #include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); t = new QThread(); //QThread obj = new MyObj(); obj->moveToThread(t); qDebug()<<"main thread:"<<QThread::currentThread(); connect(t,SIGNAL(started()), obj, SLOT(doWork())); connect(obj,SIGNAL

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值