zoukankan      html  css  js  c++  java
  • 解析Qt元对象系统(五) Q_INVOKABLE与invokeMethod(automatic connection从Qt4.8开始的解释已经与之前不同,发送对象驻足于哪一个线程并不重要,起到决定作用的是接收者对象所驻足的线程以及发射信号(该信号与接受者连接)的线程是不是在同一个线程)good

    概述
    查看Qt源码可知,Q_INVOKABLE是个空宏,目的在于让moc识别。
    使用Q_INVOKABLE来修饰成员函数,目的在于被修饰的成员函数能够被元对象系统所唤起。
    Q_INVOKABLE与QMetaObject::invokeMethod均由元对象系统唤起。这一机制在Qt C++/QML混合编程,跨线程编程,Qt Service Framework 以及 Qt/ HTML5混合编程以及里广泛使用。

    QMetaObject::invokeMethod的声明如下,还有几个inline重载:

    static bool invokeMethod(QObject *obj, const char *member,
    Qt::ConnectionType,
    QGenericReturnArgument ret,
    QGenericArgument val0 = QGenericArgument(Q_NULLPTR),
    ...... //后面还有9个参数
    1
    2
    3
    4
    5
    函数为静态函数,用法是尝试调用对象obj的方法member(注意member可以为信号或者是槽),如何member可以被调用,则返回真,否则返回假。QMetaObject::invokeMethod可以是异步调用,也可以是同步调用。这取决与它的连接方式Qt::ConnectionType type。如果type为Qt::DirectConnection,则为同步调用,若为Qt::QueuedConnection,则为异步调用。

    调用机制
    direct connection 是指:发起信号的线程会直接触发其所连接的槽;
    queued connection 是指:一个事件被派发到接收者所在的线程中,在这里,事件循环会之后的某一时间将该事件拾起并引起槽的调用;
    blocking queued connection 与queued connection的区别在于,发送者的线程会被阻塞,直至接收者所在线程的事件循环处理发送者发送(入栈)的事件,当连接信号的槽被触发后,阻塞被解除;
    automatic connection (缺省默认参数) 是指: 如果接收者所依附的线程和当前线程是同一个线程,direct connection会被使用。否则使用queued connection。
    从Qt4.8开始的解释已经与之前不同,发送对象驻足于哪一个线程并不重要,发送者对象本身在哪一个线程对与信号槽连接类型不起任何作用,起到决定作用的是接收者对象所驻足的线程以及发射信号(该信号与接受者连接)的线程是不是在同一个线程。
    看源码,发现invokeMethod最后调用QMetaMethod::invoke,在这里检查连接类型:

    // 处理自动连接的情况
    QThread *currentThread = QThread::currentThread();
    QThread *objectThread = object->thread();
    if (connectionType == Qt::AutoConnection) {
    connectionType = currentThread == objectThread
    ? Qt::DirectConnection
    : Qt::QueuedConnection;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    对直接连接,直接调 metacall,它进而去调用对象的qt_metacall:

    if (connectionType == Qt::DirectConnection) {
    return QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, methodIndex, param) < 0;
    1
    2
    对于队列连接,实际用的是postEvent派发了一个 QMetaCallEvent事件,也就是异步调用,这才能实现跨线程发送事件:

    if (connectionType == Qt::QueuedConnection)
    { . . . . . .
    QCoreApplication::postEvent(object, new QMetaCallEvent(idx_offset, idx_relative, callFunction,
    0, -1, nargs, types, args));
    }
    1
    2
    3
    4
    5
    常用的形式
    QMetaObject::invokeMethod(object, "methodName", Qt::QueuedConnection,
    Q_ARG(type1, arg1),
    Q_ARG(type2, arg2));
    1
    2
    3
    还有一种是没有第三个参数,也就是不指明信号与槽的连接方式。

    请注意,因为上面所示的参数需要被在构建事件时进行硬拷贝,参数的自定义型别所对应的类需要提供一个共有的构造函数、析构函数以及拷贝构造函数。而且必须使用注册Qt型别系统所提供的qRegisterMetaType() 方法来注册这一自定义型别。
    ---------------------
    作者:SilentAssassin
    来源:CSDN
    原文:https://blog.csdn.net/yao5hed/article/details/81142365?utm_source=copy
    版权声明:本文为博主原创文章,转载请附上博文链接!

     之前我就问过,thread对象本身属于主线程(没有使用moveToThread),它使用自己的成员变量对象(所以也属于主线程)发射信号(哪怕是在run()函数里发射),它所连接的槽函数是主线程里的函数,那么这个函数是异步执行,还是同步执行?根据这篇文章上的答案是,同步执行 
  • 相关阅读:
    魔兽70TBC猎人常用宏
    魔兽70TBC猎人宝宝技能汇总
    redis常用概念
    mongodb分片集群开启安全认证
    mongodb集群搭建(分片+副本)
    mongodb 用户权限控制
    greenplum数据迁移
    greenplum资源队列
    GreenPlum 集群常用命令
    COCOS 实现Player玩家控制的左右控制,实现马里奥一样的移动
  • 原文地址:https://www.cnblogs.com/findumars/p/9799983.html
Copyright © 2011-2022 走看看