Multithreading – the QApplication thread is frozen due to another qthread

In my QT application, I created a qthread, which should perform some heavy computing tasks regularly The main Q application thread should maintain the GUI (not included in the example) and perform some periodic updates Both threads have their own timers to enable regular update () calls

Problem: my main thread stops receiving timer events when the computing workload of the worker thread exceeds a certain threshold

The example code is as follows When the main thread calls update(), it outputs "main" and the worker thread calls "worker" If you run it, you will see that the "worker" prints regularly and the "master" appears exactly twice (one at the beginning and one in about 5 seconds) In the case of a full - featured GUI application, this actually means a complete GUI freeze

Some observations

>Reducing the workload by setting a 100 limit on the inner loop (instead of 1000) will solve the problem (the two update () methods will be called periodically). > Setting the connection type of the worker timer signal to QT:: directconnection will solve the problem

So, you can see that I have several solutions, but I'm grateful for someone to explain what the problem with my original code is I want threads to execute their event loops independently I know I block the worker thread event loop through a long update () operation, but why does it affect the main thread?

PS: Yes, I know the qcconcurrent alternative But I just want to understand

TEST. CPP

#include <windows.h>
#include <QApplication>

#include "test.h"

HANDLE mainThread_ = INVALID_HANDLE_VALUE;
QApplication *app_ = 0;
MyObj *obj_ = 0;
MyThread *thread_ = 0;

MyObj::MyObj()
    : timer_(0)
{
    timer_ = new QTimer(0);
    connect(timer_,SIGNAL(timeout()),this,SLOT(update()));
    timer_->start(10);
}

void MyObj::update()
{
    printf("Main\n");
}

void MyThread::run()
{
    timer_ = new QTimer(0);
    connect(timer_,SLOT(update()));
    timer_->start(10);

    exec();
}

void MyThread::update()
{
    printf("Worker\n");

    // do some hard work
    float f = 0.f;
    for (int i=0; i < 100000; ++i)
    {
        for (int j=0; j < 1000; ++j)
        {
            f += i * j;
        }
    }
}

int main()
{
    int argc = 0;
    app_ = new QApplication(argc,0);

    obj_ = new MyObj();
    thread_ = new MyThread();
    thread_->start();

    QApplication::exec();

    return 0;
}

test. h

#include <QTimer>
#include <QThread>

class MyObj : public QObject
{
    Q_OBJECT

public:
    MyObj();

public slots:
    void update();

private:
    QTimer *timer_;
};

class MyThread : public QThread
{
    Q_OBJECT

public:
    void run();

public slots:
    void update();

private:
    QTimer *timer_;
};

UPD: I got some answers from distinguished members (see below) Now I'd like to clarify that the wrong idea especially destroys my code

As you can see, the plan has two threads, each of which runs some update () processes periodically My mistake is to think of update () as a process, which is a slot A slot of a specific object that has its own thread affinity, which means that its body will execute in this thread (unless QT:: directconnection is used to schedule signals) Now, it seems that I've done it with a timer - each belongs to a different thread - but I screwed up with update () So I finally executed two update () programs in the main thread Obviously, at some point, the event loop will be flooded with timer events and will never complete the iteration

As for the solution If you have read "you're doing it wrong" (and you really should), you know that it is very convenient to implement all logic in one object. The object is not inherited from qthread, but created separately and connected to qthread using movetothread() I personally think that if you remember that your object only controls threads but does not belong to it, it is no problem to inherit subclasses from qthread Therefore, it is not where you want the code to execute in this thread

Solution

The first problem here is that you inherit from qthread because it declares here, "you're doing it wrong"

The problem you encounter stems from thread Association (the thread running the object) For example, if you want to inherit from qthread and create an object in the constructor without Parenting the object, the object will run in the main thread, not in the new thread So in the myThread constructor, you will have: –

MyThread::MyThread()
    : timer_(0)
{
    timer_ = new QTimer(0);
    connect(timer_,SLOT(update()));
    timer_->start(10);
}

Here's the timer () Will run on the main thread instead of the new thread In order to avoid repeating myself, one of my previous answers explained thread affinity here

The best way to solve the problem is to change the class to inherit from QObject, and then move the object to a new thread

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>