zoukankan      html  css  js  c++  java
  • 对QT多线程以及事件投递的理解

    1、使用QObject子类的movetothread方法 代替 QThread子类的run 实现多线程。
    使用原始QThread对象的start方法启动线程==>连接原始QThread对象的started信号到QObject子类的槽(线程部分)
     
    2、有parent的object是不能moveToThread被移动到其他线程中的,所以还需要把子类对象给setParent(NULL)一下再moveToThread。
     
    3、QObject子类对象在movetothread后,不要在线程中进行delete,因为QObject子类对象的内存管理还属于主线程。
     
    4、QCoreApplication::exec()开启了主线程的事件循环。子线程也是一样,需要通过调用exec开启事件循环,否则事件不会分发给对对象。
    QThread线程并不存在exec()函数。原因是exec()函数在QThread的run()中已经调用了。
     
    5、postEvent: 可以给别的线程发送事件。事件会在目的对象所属的线程中运行。异步接口。
    sendEvent: 仅用于同一个线程之间发送事件。目的对象必须与当前线程一样。同步接口
     
    6、跨线程的事件传递可以通过 QCoreApplication::postEvent重载QObject类的customEvent的方法 实现。
     
    --------------------------------------------------------------------------------------------------------------------
     
    1) 用原始的QThreadstarted信号触发自定义的slot启动线程(需要connect这个QThread对象的started信号)
    而不是派生QThread的类重载run函数启动线程。
    将一个类派生自QObject,然后实现所有的signal/slot,然后通过调用movetothread函数来使他们执行在新的线程里面,
    而不是每次都要重新派生QThread,并且派生QThread的另外一个不好的地方是只有run函数内部的代码才会执行在新线程里面,
    相比起来,派生QObject并使用movetothread函数更具有灵活性
     
    2) 自定义对象(QObject子类)moveToThread进线程后,事件循环可以完全在此线程中运行。而它的内存管理应该还属于主线程
    有parent的object是不能moveToThread被移动到其他线程中的,所以还需要把子类对象给setParent(NULL)一下再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
     
    代码片段如下:(完整例子请到转载地址查看)
    const QEvent::Type CustomEvent_Login = ( QEvent::Type )5001; //! 建议用5000以上唯一的标识

    void MyObject::customEvent( QEvent *e )
    {
        if ( e->type() == CustomEvent_Login ) //捕获消息
        {
            qDebug() << QString( "[%1]catch the event: %2!" )
                     .arg( ( qlonglong )QThread::currentThreadId() )
                     .arg( e->type() );
        }
    }

    int main( int argc, char *argv[] )
    {
        QCoreApplication a( argc, argv );
        qDebug() << "main:" << ( qlonglong )QThread::currentThreadId();

        //把业务逻辑对象设置进线程,不要把Qthread放进自己线程,这样的写法不建议。
        //绑定的时候最好设置QueuedConnection。这样就允许在myObj线程执行,否则可能会在主线程执行。
        //如果希望不要再子线程执行,用DirectConnection。
        MyObject *myObj = new MyObject;
        QThread *thread = new QThread();
        myObj->moveToThread( thread );
        thread->start();
        QObject::connect( thread, SIGNAL( started() ), myObj, SLOT( OnStartedSlot() ), Qt::QueuedConnection );

        //定时器
        //MyObject::Started/MyObject::Timeout/都会在同一个子线程调用。
        QTimer *timer = new QTimer();
        QObject::connect( timer, SIGNAL( timeout() ), myObj, SLOT( OnTimeoutSlot() ), 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 );

        return a.exec();
    }

     
    转载地址:http://blog.csdn.net/shaochat/article/details/41956707?utm_source=tuicool
    http://blog.csdn.net/sonydvd123/article/details/8660624
     
     
  • 相关阅读:
    表单自动填充autocomplete的兼容性方案
    函数的默认参数值
    利用zookeeper搭建hadoop HA集群
    zookeeper设置开机启动项
    zookeeper集群挂了的恢复流程
    zookeeper集群搭建
    docker 安装ElasticSearch的中文分词器IK
    [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
    把mysql服务设置开机启动项
    docker-compose的使用
  • 原文地址:https://www.cnblogs.com/cthu/p/5135862.html
Copyright © 2011-2022 走看看