0

I'm trying to call a method of another thread (not the Main), using invokeMethod. Unfortunately that makes the application crash as soon as it tries to execute the invokeMethod!

Am I mistaking something?

// main.cpp

#include <QtCore>
#include "entrypointclass.h"
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    qDebug() << a.thread()->currentThreadId() << " - Application started.";

    EntryPointClass entryPoint;
    entryPoint.runInNewThread();
    return a.exec();
}

// Entrypoint.h

#ifndef ENTRYPOINTCLASS_H
#define ENTRYPOINTCLASS_H

#include "worker.h"
#include <QtCore>

class EntryPointClass : public QObject
{
    Q_OBJECT
public:
    EntryPointClass();
    ~EntryPointClass();
    void runInNewThread();
public slots:
    void timeoutExpired();
private:
    Worker* m_Worker;
    QThread* m_Thread;
};

#endif // ENTRYPOINTCLASS_H

// Entrypoint.cpp

#include <QTCore>
#include "entrypointclass.h"
#include "Worker.h"

EntryPointClass::EntryPointClass()
{
    qDebug() << "EntryPointClass created";



}

EntryPointClass::~EntryPointClass()
{
    qDebug() << "EntryPointClass destroyed";
}

void EntryPointClass::runInNewThread()
{
    QThread* m_Thread = new QThread;
    Worker* m_Worker = new Worker();


    connect(m_Thread, SIGNAL(started()), m_Worker, SLOT(doSomething()));
    connect(m_Worker, SIGNAL(finished()), m_Thread, SLOT(quit()));
    connect(m_Thread, SIGNAL(finished()), m_Thread, SLOT(deleteLater()));
    connect(m_Thread, SIGNAL(finished()), m_Worker, SLOT(deleteLater()));

    QTimer* timer = new QTimer;
    timer->setSingleShot(true);

    //bool bOK = connect(timer, SIGNAL(timeout()), m_Worker, SLOT(closeWorker()), Qt::BlockingQueuedConnection);

    connect(timer, SIGNAL(timeout()), this, SLOT(timeoutExpired()));

    m_Worker->moveToThread(m_Thread);
    m_Thread->start();
    timer->start(5000);

}

void EntryPointClass::timeoutExpired()
{
    qDebug() << "timeout expired";
    if (m_Worker != NULL)
    {
        QMetaObject::invokeMethod(m_Worker, "closeWorker", Qt::QueuedConnection);
    }
}

// Worker.h

#ifndef WORKER_H
#define WORKER_H

#include <QtCore>

class Worker : public QObject
{
    Q_OBJECT
public:
    Worker();
    ~Worker();

public slots:
    void doSomething();
    void closeWorker();

private:
    bool m_bAbort;
    QMutex m_mutex;


signals:
    void finished();
};

#endif // WORKER_H

// Worker.cpp

#include "worker.h"
#include <unistd.h>
#include "QTcore"

Worker::Worker()
    : m_mutex()
{
    qDebug() << this->thread()->currentThreadId() << "Worker created";
    m_bAbort = false;
    //qDebug() << QString("Thread %1 - Worker created").arg("");//this->thread()->currentThreadId());
}

Worker::~Worker()
{
    qDebug() << this->thread()->currentThreadId() << "Worker destroyed";

}

void Worker::doSomething()
{
    while(!m_bAbort)
    {
        sleep(2);
        qDebug() << this->thread()->currentThreadId() << "Do Something!";
    }

    emit finished();
}

void Worker::closeWorker()
{
    qDebug() << this->thread()->currentThreadId() << "closeWorker triggered!";
    QMutexLocker mutexLocker(&m_mutex);
    m_bAbort = true;
}
  • ``QtQueuedConnection`` makes the method being called in the event loop of the target thread. Since you stay in a while-loop ``doSomething()`` your thread never gets to the close-worker call in the event loop. You could try calling ``processEvents()`` or call the ``closeWorker`` Method in the source thread directly. – Sebastian Lange Mar 10 '14 at 06:57
  • Why use invokeMethod, rather than connecting a signal to the slot and just emitting that signal? – TheDarkKnight Mar 10 '14 at 11:55

1 Answers1

0

Instead of invoking a method directly, try posting a custom event. This will require that you implement an event filter at the target that handles your custom event. Event posting always works as long as an event loop is active in the target thread.

Take a look at this answer here too. Also here. Hope this helps.

Community
  • 1
  • 1
DNT
  • 2,356
  • 14
  • 16