Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to connect between QThread with finished() signal for multiple Qthread

I have a 3 QThreads invoking by one another (all inherited from QThread. I know some might suggest to use moveToThread, but just ignore this fact for now). The simplified code looks like following:

Thread1 class:

void
Thread1::run
{
    // some execution
    Thread2 t2 = new Thread2();
    connect(t2,SIGNAL(finished),this,SLOT(onFinished));
    t2->start();

    while(!stop)  // stop was initialized as false
    {
        this->msleep(10);
    }    
}
void Thread1::onFinished(){ stop = true; }

Thread2 class:

void
Thread2::run
{
    // some execution
    Thread3 t3 = new Thread3();
    connect(t3,SIGNAL(finished),this,SLOT(onFinished));
    t3->start();

    while(!stop)  // stop was initialized as false
    {
        this->msleep(10);
    }    
}
void Thread2::onFinished(){ stop = true; }

Thread3 class:

void
Thread3::run
{
    // some execution
    QMutexLocker ml(&mMutex);
}

When I have only two threads, it works perfectly fine (e.g. just thread2 and thread3). The onFinished() method seems not connecting with finished() signal properly anymore, after I moved to a three-threads scenario. The onFinished() in thread2 has ever been called. And I am pretty sure the execution of the thread3 has completed.

Can anybody tell me where I could have done wrong?

like image 755
John Yang Avatar asked Mar 23 '23 01:03

John Yang


1 Answers

First of all you should note that the default connection type is Qt::AutoConnection. This means if signal is emitted from a different thread than the receiving object's thread, Qt::QueuedConnection is used. In this case: The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread. So you need an event loop.

It works with 2 threads because you probably have an event loop running in your main thread. In your case where you use only thread2 and thread3 objects, thread2 object will actually live in the main thread, while thread3 object will live in the thread managed by the thread2 object. So slots in thread2 object should work.

But in the case of 3 threads, thread1 object would live in the main thread, thread2 object would live in the thread managed by thread1 object, and because there is no running event loop there, the slot in thread2 object will never be executed.

You can call QThread::exec() in your QThread::run() function, but note that the slots will be executed in the thread where your QThread object lives in, not the thread it manages. Because of this you shouldn't use slots in QThread subclasses. You should create a QObject subclass and move it to a thread.

Another option is to use Qt::DirectConnection for the connection type, when you connect your signals to slots.

like image 148
thuga Avatar answered Apr 26 '23 19:04

thuga