How to Emit Cross-Thread Signal in Qt

How to emit cross-thread signal in Qt?

There are quite a few problems with your code :

  • like said by Evan the emit keyword is missing
  • all your objects live in the main thread, only the code in the run methods live in other threads, which means that the MySlot slot would be called in the main thread and I'm not sure that's what you want
  • your slot will never be called since the main event loop will never been launched : your two calls to wait() will only timeout after a very long time (and you'll probably kill your application before that happens) and I don't think that's what you want either, anyway they really have no use in your code.

This code would most likely work (though I have not tested it) and I think it does what you want it to do :

class MyObject : public QObject
{
Q_OBJECT
public slots:
void MySlot( void )
{
std::cout << "slot called" << std::endl;
}
};

class CThread1 : public QThread
{
Q_OBJECT
public:
void run( void )
{
std::cout << "thread 1 started" << std::endl;
int i = 0;
while(1)
{
msleep( 200 );
i++;
if(i==1000)
emit MySignal();
}
}
signals:
void MySignal( void );
};

class CThread2 : public QThread
{
Q_OBJECT
public:
void run( void )
{
std::cout << "thread 2 started" << std::endl;
exec();
}
};

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
CThread1 oThread1;
CThread2 oThread2;
MyObject myObject;
QObject::connect( & oThread1, SIGNAL( MySignal() ),
& myObject, SLOT( MySlot() ) );
oThread2.start();
myObject.moveToThread(&oThread2)
oThread1.start();
return a.exec();
}

Now MyObject will live in thread2 (thanks to moveToThread).

MySignal should be sent from thread1 (thought I'm not sure on that one, it might be sent from main thread, it doesn't really matter).

No event loop is needed in thread1 since emitting a signal doesn't need an event loop. An event loop is needed in thread2 (lanched by exec()) to receive the signal.

MySlot will be called in thread2.

Qt5 cross-threads signal and slot

Found the problem, Worker::process was indeed blocking the event loop.

How to signal a slot in another thread in Qt

You've got it backwards. A QThread is a thread handle, not a thread itself. If you want to run something in another thread, it belongs in a plain QObject that you move to a thread. You don't need to derive from QThread at all! You also shouldn't move a QThread's base QObject to the thread itself. What you do is have a handle to the thread live in the thread itself. As soon as the thread finishes, the handle becomes non-functional (a QObject with a null thread()).

First of all, if all you need is to run some code that runs to completion (e.g. does a calculation) in a worker thread, use the thread pool and QtConcurrent framework. It manages all the threads for you:

#include <QtConcurrent>
...
QThread::currentThread()->setObjectName("main");
qDebug() << QThread::currentThread();
QtConcurrent::run([]{ qDebug() << QThread::currentThread(); }

If you insist on controlling the thread's lifetime yourself, you'd do the following:

#include <QtCore>
struct Worker : QObject {
Q_SLOT void aSlot() {
qDebug() << QThread::currentThread();
QThread::currentThread()->quit();
}
Q_SIGNAL void aSignal();
Q_OBJECT
};

int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
QThread::currentThread()->setObjectName("main");
QThread thread;
thread.setObjectName("thread");
Worker a, b;
b.moveToThread(&thread);
thread.start();
QObject::connect(&a, &Worker::aSignal, &b, &Worker::aSlot);
emit a.aSignal(); // the signal is emitted from the main thread
thread.wait();
}

Finally, note that the QDebug class knows how to output the object's address, class and name (if set) when passed a pointer to a QObject. Thus, you don't need to use QThread::currentThreadId(), the QThread::currentThread() is sufficient - and you can give the threads mnemonic names since they are QObjects, after all.

Could one thread get the signal from the other one in the qt?

I've found the issue in your code.

If the QOjbect is moved to the thread, they have different Event Loop.
Your dowork() function have the infinite loop.

So this blocks the Event Loop of the backthread.

So it couldn't get any signal from the other thread.

You have not to use the infinite loop in the slot of the QOjbect it blocks the Event Loop.

  void dowork(){
//This is called by signal 'signal_dowork()'
APIManager * manager = new APIManager;
connect(manager, SIGNAL(readyResult(QNetworkReply*)), this, SLOT(on_readyResult(QNeworkReply*)));
connect(this, SIGNAL(signal_callAPI(QString)), manager, SLOT(callAPI(QString)));
connect(manager, SIGNAL(readyResult(QNetworkReply*)), manager, SLOT(terminate())); //Here api call is needed only one time.
manager->start();
while(true){ //This blocks the event loop. Event Loop couldn't get any signal from the other thread.
QThread::sleep(20);
emit signal_callAPI("http://url.com");
}
}

Without while command, that works smoothly.
Hope this will help you.



Related Topics



Leave a reply



Submit