Qt-QThread与QObject使用需要注意的点

  • QThread继承于QObject,代表一个线程,每个线程都有自己的事件循环。

  • 初始线程通过QCoreApplication::exec()开启事件循环,单dialog应用通过QDialog::exec()开启,其他线程通过QThread::exec()开启

  • 每个QObject对象都生存(live)于其被创建的线程中。查看QObject对象所在线程可调用thread()

  • QObject::moveToThread()可改变对象的线程亲和性(thread affinity)。如果有父对象则不能move。

  • 在非QObject对象所属线程delete该对象是不安全的,除非能保证该对象没有正在处理事件(events),应使用deleteLater

  • 如果事件循环没有在运行,事件将不会传递给对象。线程安全函数QCoreApplication::postEvent()可以在任意线程手动传递传递给任意对象事件。QCoreApplication::sendEvent()则只能给同线程的对象传递事件。

  • 事件过滤器(Event filter)要求监控与被监控对象处于同一个线程中

  • QObject不是线程安全的,因此在非对象所属线程中调用该对象函数且对象可能在处理事件时,应该加锁,否则可能导致崩溃。

  • QObject类可重入,其大部分非UI子类也是**可重入(reentrant)**的,可重入(reentrant)意味着在不同线程中创建若干个QObject实例能同时各自调用。这些类被设计为在单一线程中使用,这意味着我们不能在A线程中创建对象而在B线程中调用其函数

  • 有三条约束规则

    1. QObject对象的孩子必须在"其父对象所创建的线程中"创建
    2. 事件驱动对象只能用于单线程
    3. QThread线程删除所有在线程内创建的对象
  • GUI类必须在主线程中使用

  • QObject必须在QApplication创建后使用,这意味着不存在static的QObject类

  • 信号槽机制、线程、事件循环在不同连接类型下的关系

    • Qt::DirectConnection。信号发送时所在线程与槽对象所在线程相同,等价于在信号发送处替换为槽函数调用,不需要事件循环参与

    • Qt::QueuedConnection。信号发送时所在线程与槽对象线程不同,此时会发送一个事件到槽对象所在线程的事件队列。同线程将导致死锁

    • Qt::BlockingQueuedConnection。与Qt::QueuedConnection相同,但信号发送线程将阻塞直到槽函数执行并返回。

    • Qt::AutoConnection。根据发送信号时所在线程与槽对象所在线程判断使用Qt::DirectConnection或Qt::QueuedConnection

    • Qt::UniqueConnection。与Auto Connection相同,不同的地方在于如果已经存在完全相同的连接,则不进行连接。

槽函数总在槽对象所在线程执行

QThread设计本意是管理线程,并且通常是从QThread对象创建时所在线程去管理其他线程,在Qthread子类中定义信号是合理的,因为run()执行过程中可能需要发送信号到其他线程,而Qthread子类中定义槽通常是不合理的,因为槽函数不会在另外的线程中执行。如果希望某个槽函数在其他线程中执行,可以将其封装为QObject对象,并将其moveToThread到其他线程中。

参考:

  1. https://doc.qt.io/qt-5/threads-qobject.html
  2. https://wiki.qt.io/Threads_Events_QObjects

你可能感兴趣的:(Qt,qt,开发语言,多线程,QThread)