I am trying to run a separate thread from the main thread where mqttclient is initialised and moved to a new thread.
Previously there were problems of signal slot. Which i resumed by creating a separate class (mqtthandler) running from main thread and connected to mqttclient class via signal slots which are delivered to qml.
I tested the codes by running them in same thread. They all work.
Now when I tried to move mqttclient in another thread it causes problem. I know the reason why it is giving me the problem but I dont know, the solution to it.
The problem creator is mqttclient constructor because it connecttohost in constructor only. I need to connecttohost mqttclient but somehow in new thread.
I also tried to make connecttohost in subscribe function (of mqttclient itself) which at later stage is called via mqtthandler which is called by qml. Still it doesnt work.
main.cpp
QGuiApplication app(argc, argv);
QThread mqttclientThread;
// When the application is quitting, so should the worker thread
QObject::connect(&app, &QCoreApplication::aboutToQuit, &mqttclientThread, &QThread::quit);
MqttClient * mqttclientObj = new MqttClient;
mqttclientObj->moveToThread(&mqttclientThread);
mqttclientThread.start();
qDebug() << "Main client status " << mqttclientObj->state();
MqttHandler * mqttHandlerObj = new MqttHandler;
QObject::connect(mqttHandlerObj, &MqttHandler::mqtthandler_getaddr_signal, mqttclientObj, &MqttClient::getAddr);
QObject::connect(mqttclientObj, &MqttClient::sensorValueChanged, mqttHandlerObj,&MqttHandler::mqtthandler_sensorValueChanged_slot);
qDebug() << "Main " << QThread::currentThread();
mqttclient.cpp
MqttClient::MqttClient(QObject *parent)
: QMqttClient(parent)
{
this->setHostname("127.0.0.1");
this->setPort(1883);
this->connectToHost();
m_listTopic.clear();
vSimulateSensorValues();
connect(this, SIGNAL(publishsignals(QString, QString)),this, SLOT(publishmsg(QString,QString)));
}
MqttSubscription* MqttClient::subscribe(const QString &topic)
{
auto sub = QMqttClient::subscribe(topic, 0);
MqttSubscription* result = new MqttSubscription(sub, this);
qDebug() << "subscribe " << QThread::currentThread();
m_listTopic.append(topic);
return result;
}
MqttSubscription::MqttSubscription(QMqttSubscription *s, MqttClient *c)
: sub(s),
client(c)
{
connect(sub, &QMqttSubscription::messageReceived, client, &MqttClient::handleMessage);
qDebug() << "mqttsubconn " << QThread::currentThread();
}
MqttSubscription::~MqttSubscription()
{
}
The Error
Main client status 1
Main QThread(0x7fcfa7400530)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QMqttConnection(0x7fcfa75a3008), parent's thread is QThread(0x7fcfa7400530), current thread is QThread(0x7ffee1cb4a30)
QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread
/*****************************************************************************************************************************************************************************************************************************/
Update
updated mqttclient class
MqttClient::MqttClient(QObject *parent)
: QMqttClient(parent)
{
}
void MqttClient::Init()
{
this->setHostname("127.0.0.1");
this->setPort(1883);
this->connectToHost();
QThread::sleep(10);
m_listTopic.clear();
vSimulateSensorValues();
connect(this, &MqttClient::publishsignals, this, &MqttClient::publishmsg);
}
MqttSubscription* MqttClient::subscribe(const QString &topic)
{
// this->setParent(this);
auto sub = QMqttClient::subscribe(topic, 0);
qDebug() << "state " << this->state();
MqttSubscription* result = new MqttSubscription(sub, this);
qDebug() << "subscribe " << QThread::currentThread();
m_listTopic.append(topic);
return result;
}
void MqttClient::handleMessage(const QMqttMessage &qmsg)
{
emit MqttClient::sensorValueChanged(qmsg.payload(),qmsg.topic().name());
qDebug() << "Handle " << QThread::currentThread();
}
void MqttClient::getAddr(QString value)
{
qDebug() << "c++ " + value;
subscribe(value);
qDebug() << "getaddr " << QThread::currentThread();
}
MqttSubscription::MqttSubscription(QMqttSubscription *s, MqttClient *c)
: sub(s),
client(c)
{
qDebug() << "Here " << client->state();
qDebug() << client;
connect(sub, &QMqttSubscription::messageReceived, client, &MqttClient::handleMessage);
qDebug() << "mqttsubconn " << QThread::currentThread();
}
MqttSubscription::~MqttSubscription()
{
}
and main.cpp
QGuiApplication app(argc, argv);
QThread mqttclientThread;
// When the application is quitting, so should the worker thread
QObject::connect(&app, &QCoreApplication::aboutToQuit, &mqttclientThread, &QThread::quit);
MqttClient * mqttclientObj = new MqttClient;
mqttclientObj->moveToThread(&mqttclientThread);
QObject::connect(&mqttclientThread, &QThread::started, mqttclientObj, &MqttClient::Init);
mqttclientThread.start();
MqttHandler * mqttHandlerObj = new MqttHandler;
QObject::connect(mqttHandlerObj, &MqttHandler::mqtthandler_getaddr_signal, mqttclientObj, &MqttClient::getAddr);
QObject::connect(mqttclientObj, &MqttClient::sensorValueChanged, mqttHandlerObj,&MqttHandler::mqtthandler_sensorValueChanged_slot);
qDebug() << "Main " << QThread::currentThread();
The update gave rise to another problem
Main QThread(0x7f925750e790)
state 1
Here 1
MqttClient(0x7f9257600f90)
QObject::connect(QMqttSubscription, MqttClient): invalid null parameter
QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread
If the problem is, as you suggest, the call to connectToHost
in the MqttClient
constructor then why not simply move the offending code into a slot?
MqttClient::MqttClient(QObject *parent)
: QMqttClient(parent)
{
}
void MqttClient::init ()
{
this->setHostname("127.0.0.1");
this->setPort(1883);
this->connectToHost();
m_listTopic.clear();
vSimulateSensorValues();
connect(this, &MqttClient::publishsignals, this, &MqttClient::publishmsg);
}
Then in main
connect that slot to the QThread::started
signal...
.
.
.
MqttClient *mqttclientObj = new MqttClient;
mqttclientObj->moveToThread(&mqttclientThread);
/*
* Connect MqttClient::init slot to QThread::started signal.
*/
connect(&mqttclientThread, &QThread::started, mqttclientObj, &MqttClient::init);
mqttclientThread.start();
.
.
.