• qt之movetothread理解


    基础概念

    • qt的下线程qthread,每个线程都有自己的事件循环exec。
    • 对象的线程上下文,每个对象都有自己的线程上下文,怎么理解呢,就是该对象在哪个线程创建,其线程上下文就是谁。
    • 每个qobject对象在创建时都有包含线程成员,threaddata,该成员的类型是QThreadData,该成员与qobject对象的父对象保持一致,若父对象不存在,则取当前线程的值为该成员赋值,详见源码如下:
    1. QObject::QObject(QObject *parent)
    2. : d_ptr(new QObjectPrivate)
    3. {
    4. Q_D(QObject);
    5. d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current();
    6. if (parent) {
    7. if (!check_parent_thread(parent, parent ? parent->d_func()->threadData : 0, d->threadData))
    8. parent = 0;
    9. setParent(parent);
    10. }

     如上代码可以得出如下结论:

    • 当创建QObject时,在构造函数中会根据父对象的值进行赋值,规则是如果父对象存在,并且父对象下thread成员存在,则赋值给新创建的threadData成员;否则将当前多线程的线程数据赋值给该对象threadData成员。
    1. void QObject::moveToThread(QThread *targetThread)
    2. {
    3. Q_D(QObject);
    4. if (d->parent != 0) {
    5. qWarning("QObject::moveToThread: Cannot move objects with a parent");
    6. return;
    7. }
    8. if (d->isWidget) {
    9. qWarning("QObject::moveToThread: Widgets cannot be moved to a new thread");
    10. return;
    11. }
    12. QThreadData *currentData = QThreadData::current();
    13. QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) : new QThreadData(0);
    14. if (d->threadData->thread == 0 && currentData == targetData) {
    15. // one exception to the rule: we allow moving objects with no thread affinity to the current thread
    16. currentData = d->threadData;
    17. } else if (d->threadData != currentData) {
    18. qWarning("QObject::moveToThread: Current thread (%p) is not the object's thread (%p)./n"
    19. "Cannot move to target thread (%p)/n",
    20. currentData->thread, d->threadData->thread, targetData->thread);
    21. return;
    22. }
    23. ......

     通过如上代码可以看到movetothread的限制条件如下:

    1. 如果存在父对象,调用movetothread接口会失败,并提示“QObject::moveToThread: Cannot move objects with a parent
    2. 如果是该对象是QWidget或者其子类,不能调用movetothread,因为qwidget及其子类只能在主线程中。否则会产生“QObject::moveToThread: Widgets cannot be moved to a new thread”错误
    3. 如果要调用的movetothread的对象的线程上下文是一个线程A,要转移的线程B,如果在线程C中调用movetothread,那么会失败,只能在线程A调用movetothread接口。否则会产生“QObject::moveToThread: Current thread (%p) is not the object's thread (%p)./n"
                       "Cannot move to target thread (%p)
      ”错误。

    movetothread的本质

    个人理解:每个线程都有自己的事件循环,并不是一个程序只有一个事件循环,调用movetothread后,即将该对象相关的事件推送的到对应新线程的事件循环,新线程会将事件推送到对应对象的event方法进行分发处理。所以只有事件类型的才可以在新线程中执行(即只能通过信号槽机制来调用,因为跨线程信号槽机制会触发事件推送;在另外一个线程中通过函数调用的方式调用该对象的方法不会在新线程中执行,而是在调用线程执行)。

    重点

    movetothread是一种多线程的实现方式

    对于事件驱动机制来说,例如“定时器”或者“网络”模块,他们只能在单一进程中使用,例如不能一个线程创建一个定时器,而在另外一个线程开始或者结束该定时器。这些操作都不可取。

  • 相关阅读:
    [原创]JVM垃圾回收机制和常见垃圾收集器-CMS、G1、ZGC
    基于宽表的数据建模
    认识NR(二): 单天线阵面Type II码本生成过程
    Android 指定有线网或Wifi进行网络请求
    SQL注入
    将vue2组件发布成一个npm包
    理一理 OC/OD 门、开漏输出、推挽输出等一些相关概念
    21天挑战赛算法学习打卡——顺序查找
    Arduino ESP8266/32 自定义IO组网页状态显示与控制
    selenium上传文件时打开指定本地文件路径
  • 原文地址:https://blog.csdn.net/iqanchao/article/details/132756714