1
votes

I've tried to use an approach from https://wiki.qt.io/QThreads_general_usage with moveToThread. Everything is fine. But if I try to add the argument to the finished signal, there is the following problem:

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);
}

The main class is:

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();
}

If I connect this finished signal to some slot (slotFinished), I didn't get the call of this slot.

Is it an expected behavior of the signals/slots/moveToThread?

1
Please edit your question to provide a minimal reproducible example. Based on the code shown there's no reason the slot shouldn't be called with the specified parameter.G.M.
change to void process(const QString & message); and void finished(const QString& value); and void Main::slotFinished(const QString & value) { qDebug() << "result " << value; }eyllanesc
In such a case I've got a compiler problem with the line: connect(thread, &QThread::started, worker, &ThreadWorker::process); However, if I change it to connect(thread, &QThread::started, [&](){worker->process("");}); I've got runtime error in application.Borys L.
You can probably leave process as void process() -- it doesn't appear to need any parameters.G.M.
The last result, I've got: argument passing in signal/slot really works with QString, but not with the std::string. A little bit strange :)Borys L.

1 Answers

2
votes

Problem is meta data information.

When you do a default connection between signal and slot and when signal is emitted from different thread than receiver is assigned to, Qt does a magic and wraps arguments for signal (creates a copy) and queue them in event loop of destination thread.

Then when destination tread executes logic of the Qt event loop, values are unwrapped and respective slot is invoked with copied values.

Now to be able to do this copy, Qt has to have some minimal knowledge about that type. So when you use Qt types it will work out of the box, but you use external types like std::string in your case, you have to first perform type registration.

So basically your code is missing something like this:

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

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

Without type registration Qt doesn't know how to do a copy and provides a warning in logs. Check Qt logs I'm sure it prompts you with proper error message.