QApplication thread hangs due to another QThread

In my Qt application, I create QThread , which has to do some heavy computation task regularly. The main QApplication thread should support a graphical interface (not included in the example) and perform some regular updates. Both threads have their own timers to provide regular updates () calls.

Problem: When the workload for the workflow exceeds some critical value, my main thread stops receiving timer events.

The following is sample code. It returns "Main" when update () is called for the main thread, and "Worker" for the worker thread. If you run it, you will see that “Worker” is printed regularly, and “Main” appears exactly two times (one at the beginning and one after about 5 seconds). In the case of a full-featured GUI application, this may mean the GUI is completely frozen.

Some observations.

  • Reducing the workload by setting the 100 internal loop limit (instead of 1000) will fix the problem (both update () methods will be called regularly).
  • Setting the connection type for the thread workflow signal for Qt :: DirectConnection will fix the problem.

So, as you can see, I have a few workarounds, but I would appreciate it if someone would explain to me that the problem is with the source code. I expect threads to execute their event loops independently. I know that I am blocking the workflow event loop with the long update () operation, but why in the world does this affect the main thread?

PS Yes, I know an alternative to QConcurrent . But I just wanted 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_, SIGNAL(timeout()), this, 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 have answers from respected members (read them below). Now I would like to clarify which bad idea violated my code in particular.

As you can see, there were two threads in the plan, each of which regularly performed some update () procedure. My mistake was to update () as soon as some procedure, and this is a slot . The slot of a specific object that has its own proximity to the stream, which means that its body will execute in this stream (if the signal is not sent with Qt :: DirectConnection). Now it seems that I did everything correctly with the timers - each of them belongs to a different thread, but confused things with update (). Therefore, I ended up executing both update () procedures in the main thread. Apparently, at some point, the event loop is flooded with timer events and never ends the iteration.

As for the decisions. If you read “You are doing it wrong” (and you really should), you know that it’s quite convenient to implement all your logic in an object that is not subclassed from QThread but created separately and attached to QThread using moveToThread (). Personally, I don’t see anything bad in a subclass of QThread, if you remember that your object controls the thread, but does not belong to it. So this is not the place for the code you want to execute on this thread.

+7
multithreading qt qthread qtcore
source share
2 answers

The first problem is that you inherit QThread, since here you are "mistaken".

Problems arising due to the proximity of the thread (in the thread of which the object is running). For example, if you must inherit from QThread and create objects in the constructor without a parent object, this object will work in the main thread, and not in the new thread. Therefore, in the constructor of MyThread you will have: -

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

The timer (timer_) here will work on the main thread, and not on the new thread. To keep repeating, one of my previous answers explains the affinity of the thread here .

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

+3
source share

first of all ... http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/

from your main I don’t see anything like the GUI ... you just call QApplication::exec() for some reason not app_->exec() (?)

for your doUpdate() problem: you can create a QObject based class that has a doUpdate() slot or so. with this you can do it like:

 TheUpdateObject* obj = new TheUpdateObject; obj->moveToThread(thread_); // thread_ is a QThread object thread_->start(); connect(thread_, SIGNAL(finished()), obj, SLOT(deleteLater())); QTimer* tmr = new QTimer(this); tmr->setTimeout(10); connect(tmr, SIGNAL(timeout()), obj, SLOT(doUpdate())); connect(tmr, SIGNAL(timeout()), tmr, SLOT(start())); tmr->start(); 

therefore, the timer must restart itself, and doUpdate() must be called on another thread.

inside a GUI that you don’t need to check for updates, the qt framework should be redrawn as needed.

+2
source share

All Articles