QVector <custom class =“”>连接线程无法对类型的参数进行排队

时间:2015-12-03 18:32:46

标签: c++ multithreading qt metadata slots

我有问题。 我有一个自定义类BasicSpace。此类不是qobject(没有宏),并且不由qobject继承。这是一个简单的类,有一些数据,qtime等。 我有:

connect(connector,SIGNAL(finishedReadData(QVector<BasicSpace>&)),&window,SLOT(updateData(QVector<BasicSpace>&)));

我试试

qRegisterMetaType< QVector<BasicSpace> >("QVector<BasicSpace>");
main.cpp中的

但Qt仍然在调用插槽时带我发信息:

  

QObject :: connect:无法对“QVector&amp;”类型的参数进行排队   (确保使用qRegisterMetaType()注册'QVector&amp;'。)

我的注意力集中在线程上。

我的项目是高级的,所以我尝试避免使用不同名称的typedef解决方案,所以我不测试它。 有人可以帮帮我吗?

EDIT THX Frank。我将QVector替换为值的引用,没有&amp ;.这项工作,但我怀疑。它工作但线程连接总是复制数据,所以没有参考数据的prabodly是双倍复制,第一次在函数和第二次线程之间?

我认为50%已经解决了。我有工作代码,但主要问题 - 排队连接中模板类型的引用值尚未解决。

1 个答案:

答案 0 :(得分:0)

当您连接信号和位于同一线程中的对象插槽时,将使用Qt::DirectConnection类型。在这种情况下,插槽作为普通函数调用执行。您不必通过qRegisterMetaType注册数据类型,当您将数据作为参考发送时,不会复制数据。

如果发送方和接收方对象不在同一个线程中,则使用Qt::QueuedConnection类型。现在,当您发送一些数据时,无论您是按值还是通过引用发送它,都会将其复制到事件队列中。您的数据类型也必须使用qRegisterMetaType注册。

以下是一个说明此行为的简单示例:

class MyObject
{
public:
    MyObject()
    {
        qDebug() << Q_FUNC_INFO;
    }

    MyObject(const MyObject &other)
    {
        qDebug() << Q_FUNC_INFO;
    }

    ~MyObject()
    {
        qDebug() << Q_FUNC_INFO;
    }

};

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();

signals:
    void myObjectSignal1(const MyObject &obj);
    void myObjectSignal2(const MyObject &obj);

public slots:
    void testDirectConnection();
    void testQueuedConnection();

    void myObjectSlot(const MyObject &obj);

};

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    QHBoxLayout *layout = new QHBoxLayout(this);

    QPushButton *b1 = new QPushButton;
    b1->setText("direct");
    layout->addWidget(b1);
    connect(b1, SIGNAL(clicked()), this, SLOT(testDirectConnection()));

    QPushButton *b2 = new QPushButton;
    b2->setText("queued");
    layout->addWidget(b2);
    connect(b2, SIGNAL(clicked()), this, SLOT(testQueuedConnection()));

    qRegisterMetaType<MyObject>("MyObject");

    connect(this, SIGNAL(myObjectSignal1(MyObject)),
            this, SLOT(myObjectSlot(MyObject)));
    connect(this, SIGNAL(myObjectSignal2(MyObject)),
            this, SLOT(myObjectSlot(MyObject)), Qt::QueuedConnection);
}

Widget::~Widget()
{

}

void Widget::testDirectConnection()
{
    MyObject obj;
    emit myObjectSignal1(obj);
}

void Widget::testQueuedConnection()
{
    MyObject obj;
    emit myObjectSignal2(obj);
}

void Widget::myObjectSlot(const MyObject &obj)
{
}

Qt::DirectConnection方案:

  1. myObjectSignal1信号已连接到myObjectSlot Qt::DirectConnection

  2. MyObjectWidget::testDirectConnection内创建。

  3. myObjectSignal1信号触发myObjectSlot作为普通函数调用。

  4. MyObject通过引用传递到myObjectSlot
  5. myObjectSlot执行完毕。
  6. 当控件离开MyObject时,
  7. Widget::testDirectConnection被销毁。
  8. 输出将是:

    MyObject::MyObject() 
    MyObject::~MyObject() 
    

    Qt::QueuedConnection方案:

    1. myObjectSignal2信号已连接到myObjectSlot使用 Qt::QueuedConnection
    2. MyObjectWidget::testQueuedConnection内创建。

    3. myObjectSignal2信号触发器和MyObject被复制到事件队列中。

    4. 当控件离开MyObject时,
    5. Widget::testQueuedConnection被销毁。
    6. 控件返回事件循环并执行myObjectSlot,其中会获得MyObject的副本。
    7. MyObject的副本在控件离开myObjectSlot时被销毁。
    8. 输出将是:

      MyObject::MyObject() // object is created inside testQueuedConnection
      MyObject::MyObject(const MyObject&) // object is copied
      MyObject::~MyObject() // object is destroyed
      MyObject::~MyObject() // copy is destroyed
      

      如果要避免其他对象复制,可以使用new运算符为堆上的数据分配内存,然后传递指针。但在这种情况下,您必须确保在处理结束时销毁对象。

      关于在Qt信号槽连接中复制参数的好文章:http://www.embeddeduse.com/2013/06/29/copied-or-not-copied-arguments-signals-slots/