Qt moveToThread,带有参数的信号/插槽

时间:2018-08-13 12:28:35

标签: c++ qt

我尝试使用https://wiki.qt.io/QThreads_general_usage中的方法 与moveToThread。一切都好。但是,如果我尝试将参数添加到完成的信号中,则会出现以下问题:

class Worker : public QObject {
Q_OBJECT
public:
   Worker();
   ~Worker();
public slots:
   void process();
signals:
   void finished(const std::string& value);
};

void Worker::process() { // Process. Start processing data.
    // allocate resources using new here
    qDebug("Hello World!");
    std::string s = someFunctionReturningString(); 
    emit finished(s);
}

主要课程是:

class Main: public QObject {
Q_OBJECT
public:
    void startProgram();
public slots:
   void slotFinished(const std::string& s);
};

void Main::startProgram() {
   QThread* thread = new QThread;
   Worker* worker = new Worker();
   worker->moveToThread(thread);
   connect(thread, &QThread::started, worker, &Worker::process);
   connect(worker, &Worker::finished, thread, &QThread::quit);
   connect(worker, &Worker::finished, worker, &Worker::deleteLater);
   connect(worker, &Worker::finished, this,   &Main::slotFinished);
   connect(thread, &QThread::finished, thread, &QThread::deleteLater);
   thread->start();
}

void Main::slotFinished(const std::string& value) {
    qDebug() << "result " << value.c_str();
}

如果我将完成的信号连接到某个插槽(slotFinished),则不会接到该插槽的呼叫。

信号/插槽/ moveToThread是预期的行为吗?

1 个答案:

答案 0 :(得分:2)

问题是元数据信息。

当您在信号和插槽之间执行default connection时,并且当信号从与接收者所分配的线程不同的线程发出时,Qt会产生魔力并包装信号的参数(创建副本)并在事件循环中将它们排队目标线程。

然后,当目标踏点执行Qt事件循环的逻辑时,将解包值,并使用复制的值调用相应的插槽。

现在,要能够进行此复制,Qt必须对这种类型有一些基本的了解。 因此,当您使用Qt类型时,它可以立即使用,但是如果您使用std::string这样的外部类型,则必须先执行类型注册。

所以基本上您的代码缺少这样的东西:

// to be declared somewhere
Q_DECLARE_METATYPE(std::string);

// to be invoked at the beginning of program
qRegisterMetaType<std::string>();

没有类型注册,Qt不知道如何进行复制,并在日志中提供警告。检查Qt日志,我确定它会提示您正确的错误消息。