-1

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
Mandeep
  • 335
  • 3
  • 13
  • Perhaps off topic but... why do you feel you need to use threads here? Why not simply connect the various signals provided by the classes involved? – G.M. Nov 22 '19 at 12:12
  • The above mentioned codes are part of bigger project. The basic idea is to keep mqttclient in a separate thread from current main thread. The Current main thread is responsible for running ui etc. So In any case even if mqtt client is stuck broken etc should not affect the main thread. – Mandeep Nov 22 '19 at 12:25

1 Answers1

1

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();
    .
    .
    .
G.M.
  • 12,232
  • 2
  • 15
  • 18
  • Thank You for the suggestion I have updated the codes above. Your suggestion solves a bit but gave rise to another issue – Mandeep Nov 22 '19 at 13:01