QT Multithread Signals and Slots

Keywords: Qt less

Through experiments, we find that even though slot functions are defined in the thread class, the calling function is not the thread. Of course, that's not what we want. Is there any way to make the thread that calls the slot function the native thread?

We should know a few questions in the QT.

  1. Which thread does the object depend on
  2. The Relation between Object Dependency and Slot Function Execution
  3. Whether and how the dependency of objects can be changed

By default, objects are attached to threads that are created by themselves.

From the code, it is found that the main thread creates ThreadTest threada; and MyClassmy; these two objects are then attached to the main thread.

By default, slot functions are executed in threads to which the object is attached.

Object dependency can really change, and we can find such a thing from the source code.

//In QObject
void moveToThread(QThread *thread);

This method is defined in QObject, through which the dependency of objects can be changed.

Want a go

#include <QApplication>
#include <QObject>
#include <QDebug>
#include <QThread>


class MyClass : public QObject
{
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = nullptr){}

public slots:
    void getstarted()
    {
        qDebug()<<objectName()<<":"<<"getstarted() , tid :"<<QThread::currentThreadId();
    }

    void getfinished()
    {
        qDebug()<<objectName()<<":"<<"getfinished(), tid :"<<QThread::currentThreadId();
    }
    
signals:
};

class ThreadTest : public QThread
{
    Q_OBJECT
public:
    ThreadTest()
    {
        connect(this,SIGNAL(counter(int)),this,SLOT(getCounter(int)));
        connect(this,SIGNAL(counter_reset()),this,SLOT(on_counter_reset()));
    }

    void run()
    {

        qDebug()<<"ThreadTest tid"<<currentThreadId();
        int m_counter = 0;
        for(int i = 0;i<10;i++)
        {
            if(0==i%5)
            {
                m_counter = 0;
                emit counter_reset();
            }

            emit counter(m_counter);
            m_counter = m_counter + 1;
            msleep(200);
        }
    }
signals:
    void counter(int n);
    void counter_reset();

public slots:
    void getCounter(int n)
    {
        qDebug()<< "tid:"<<currentThreadId()<< " , getCounter : "<<n;
    }
    void on_counter_reset()
    {
        qDebug()<< "tid:"<<currentThreadId()<< "counter reset now !";
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    qDebug()<<"main tid:"<< QThread::currentThreadId();

    ThreadTest threada;
    MyClass my;

    my.setObjectName("my");

    QObject::connect(&threada,SIGNAL(started()),&my,SLOT(getstarted()));
    QObject::connect(&threada,SIGNAL(finished()),&my,SLOT(getfinished()));

    threada.moveToThread(&threada);
    my.moveToThread(&threada);

    threada.start();

    return a.exec();
}

Operation results

From the results of the operation, we did change the dependency of the object. However, let me remind you that the version of QT I use here is 5.12. If you use less than 4.4 version of QT, but you can not get my result. Why?

For versions 4.4 and less than 4.4 of QT s, signals and slots are defined, but slot functions cannot be invoked in sub-threads. That's because sub-threads don't open event loops, which involves the principle of the mechanism of signals and slots, drawing a simple diagram, can't draw, just look at it....

Where did the signal go after we sent it? The signal entered the event queue. But it's useless to just get into the event queue and not deal with it. It's like a customer ordering a dish and nobody tells the chef what to cook. Call exec (); the message queue can be processed after the event loop is opened.

Signals and slots need event loops to support them, because after 4.4, run calls QThread::exec() by default, which opens event loops, so we can use signals and slots normally without calling exec () in sub-threads on our own initiative. Before 4.4 (including 4.4), we need to manually open the event loop by calling QThread::exec(), so that we can use signals and slots properly.

Why change the dependency of the object? What's the point of changing dependency?

When we talked about multi-threading, we emphasized that if we use multi-threading, there may be critical resource competition. If the signal is sent and the corresponding slot function is executed in different threads, there may be competition for critical resources.

Posted by paul_so40 on Thu, 08 Aug 2019 03:58:27 -0700