I am writing an RPC-like program that uses the Qt signal slot, when using a client program to call the server, a function is executed, and I need to print the value of this function on the QtableWidget, so I use emit
to transmit signals in this function, but I find that the slot function is not executed. This seems to be related to multithreading.
update: I found that I made a mess of the code, here to simplify. I use a static class method to emit a signal so the code looks a little bit tricky.
// service.cpp file
#include "service.h"
multipleService* multipleService::getInstance = nullptr;
int add(int a, int b) {
return a + b;
}
multipleService::multipleService() {
getInstance = this; // for static method to emit signal
bool ok = connect(this, &multipleService::internalMessageOutput, this, &multipleService::messageOutputFunc, Qt::AutoConnection);
}
// implement service
void multipleService::AddService(ServiceType::Request& request, ServiceType::Response& response) {
// do some stuff ... get response
emit getInstance->internalMessageOutput(QString(response));
}
void multipleService::messageOutputFunc(QString msg) {
emit getInstance->messageOutput(msg);
}
// service.h file
#pragma once
#include <stdio.h>
#include <string.h>
// some declarations
class multipleService :public QObject {
Q_OBJECT
public:
multipleService();
~multipleService();
static void AddService(ServiceType::Request& request, ServiceType::Response& response);
void messageOutputFunc(QString);
private:
static multipleService* getInstance;
signals:
void messageOutput(QString);
void internalMessageOutput(QString);
};
And in the mainwindow.cpp
file, I use create_service
to behave like a server in RPC. And this actually works fine. once emit getInstance->internalMessageOutput(QString(response));
executes,the signal func executes.
//mainwindow.cpp in main thread
multipleService* s = new multipleService();
connect(s, &multipleService::messageOutput, this, &serviceThread::outputMessage);
auto service = node.create_service<ServiceType>(service_name, multipleService::AddService, qoS);
But I want to create a multithread so I changed the code like
// mainwindow.cpp file in main thread
QThread* thread = new QThread; //create a thread
serviceThread* myThread = new serviceThread(this);// create a class which derives from QObject and move it to the thread
//connect start signal with a lambda func
connect(thread, &QThread::started, myThread, [&myThread, SERVICE_NAME]()
{ std::string a = SERVICE_NAME;
char* AddServiceName = (char*)a.data();
myThread->createService("NODE", AddServiceName, 10);
});
// start a thread and this will call the slot func
thread->start();
myThread->moveToThread(thread);
I create a serviceThread.cpp
and new serviceThread
and move it to a thread to support multithread but emit getInstance->internalMessageOutput(QString(response))
,the slot func doesn't execute.
//serviceThread.cpp file
void serviceThread::createService(const char* nodeName, const char* service_name, int historyDepth) {
// do some declaration
multipleService* s = new multipleService();
connect(s, &multipleService::messageOutput, this,
&serviceThread::outputMessage);
auto service = node.create_service<ServiceType>(service_name,
multipleService::AddService, qos);
if (service) {
service->start();
}
else {
// error
return;
}
while (true)
{ //
if (QThread::currentThread()->isInterruptionRequested())
{
break;
}
}
}
I have tried to change the connect type to Qt::QueuedConnection
and this also failed. I also set a breakpoint on the line and it literally executed.
update: OK,I find something wrong with the while
loop in the multithread, I use QCoreApplication::processEvents(QEventLoop::AllEvents, 10);
in the loop to temporirally solve this problem. Are there any other solutions?
One of problems I see right away is mainwindow.cpp
code:
QThread* thread = new QThread; //create a thread
serviceThread* myThread = new serviceThread(this);// create a class which derives
...
myThread->moveToThread(thread); // this will silently fail.
If you look up documention on website, you must pay attention, they mentioned that. You can't move a parented QObject
and you cannot move a QWidget
at all. Since serviceThread
is a QObject
, myThread
cannot be moved - it is parented to main window now, which is part of main thread.
My usual approach to this is
QObject
-derived class, let's call it Manager
,Manager
to the worker thread,QThread
to Manager
s slots.Manager
would create the rest of objectsCode for an old project, redacted.. sorry for Qt4 style connect()
void QApp::startThreads()
{
// Just basic thread is enough here
netThread = new QThread(this);
manager = new Manager();
// IMPORTANT: Manager does not have a parent
//
// 1.moveToThread first
//
manager->moveToThread(netThread);
//
// 2. connect later. moveToThread breaks it.
//
// run main function when thread started
connect(netThread, SIGNAL(started()), manager, SLOT(start()));
// delete everything when we stop thread.
connect(netThread, SIGNAL(finished()), manager, SLOT(deleteLater()));
// Something Manager-specific, just for an example
connect(manager, SIGNAL(receivedData()), this, SLOT(updateAll()) );
connect(manager, SIGNAL(receivedStatus()), ConData, SLOT(onReceive()));
netThread->start();
}
What Manager::start
does:
void Manager::start()
{
// 1. create children objects
// 2. connect signals
}