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()函数里发射),它所连接的槽函数是主线程里的函数,那么这个函数是异步执行,还是同步执行?根据这篇文章上的答案是,同步执行 
  • 相关阅读:
    【转】【SEE】基于SSE指令集的程序设计简介
    【转】【Asp.Net】asp.net服务器控件创建
    ControlTemplate in WPF ——ScrollBar
    ControlTemplate in WPF —— Menu
    ControlTemplate in WPF —— Expander
    ControlTemplate in WPF —— TreeView
    ControlTemplate in WPF —— ListBox
    ControlTemplate in WPF —— ComboBox
    ControlTemplate in WPF —— TextBox
    ControlTemplate in WPF —— RadioButton
  • 原文地址:https://www.cnblogs.com/findumars/p/9799983.html
Copyright © 2011-2022 走看看