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.