Solved QEventLoop and threads.
-
Hi,
I have three classes, a data requester, the application controller, and the application window.During its process, in some cases, the data requester detects that one data is missing to be able to continue its process. So it emits a signal to request the missing data. Then it blocks its process (using a QEventLoop) until this data is received.
The signal is connected (using a queued connection) to a slot in the application controller. If the application controller also does not have this data, it emits a signal to request the data. (otherwise it answers immediately)
This signal is received by the application window. And the window displays a pop-up (using exec()), si that the user enters the data. Once user has finished, the data is broadcasted to the data requester that stops its event loop and continues its process.
This process works well when the three classes stand in the main thread. But, there is also cases were the data requester runs in a dedicated thread. In this case, the pop-up is diplayed but it is impossible to enter the data, or to close the window. All user actions are discarded.
Do you know why? And do you know how I can implement a wiat method that works in the two cases (requested in the main thread or a dedicated thread)?
Thanks.
-
@Alain38-0 said in QEventLoop and threads.:
runs in a dedicated thread
How are you implementing the new thread?
In this case, the pop-up is diplayed but it is impossible to enter the data, or to close the window
This looks like you are starting another event loop in the main thread after the one showing the dialog
And do you know how I can implement a wiat method that works in the two cases (requested in the main thread or a dedicated thread)?
What you are doing is already the correct way
-
Hi @VRonin,
The thread is created through a QtConcurrent. I just did different tries:
1- Now I'm creating the QEventLoop just in when needed. It was to check if the fact that it was created with the object (so on in the main thread) . But this changes nothing,
2- Much more surprising. I replaced the QEventLoop by a QMutex. And I still have the same problem.I have checked that the pop-up is executed in the main thread. It is the case. I even did a show, followed by a setFocus(), and finally the exec() to be sure that it has the focus.
More. I put a breakpoint in QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) with the condition d->queuedUserInputEvents.d->begin != d->queuedUserInputEvents.d->end. And this breakpoint never raise, as if my user events were discarded before.
-
@Alain38-0 said in QEventLoop and threads.:
The thread is created through a QtConcurrent.
Ok, here is the problem. If you create an item in the main thread and then run some methods of if, all the slots triggered by signals will be executed in the main thread (and directly if you don't force
Qt::QueuedConnection
).This is illustrated here: https://doc.qt.io/qt-5.10/threads-technologies.html#choosing-an-appropriate-approach
Your solution is to implement a worker object in a QThread like described here: https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
The rest should work as it is.
Your code is mostly correct, you just used the wrong threading technology
-
Hi @VRonin,
I explicitely set Qt::QueuedConnection. Otherwise, in any case, the process should not work when all classes are in the main thread. Because, by default the connection is direct. So the blockingLoop.exec() will be called after the end of the slot, i.e. too late.... -
Let me explain better. What I think you have is:
class DataRequester : public QObject{ // stuff public: Q_SIGNAL void iNeedData(); Q_SLOT void receiveData(const DataPoint& val){ //stuff } void calculateData(){ // stuff if(dataIsMissing){ emit iNeedData(); QEventLoop eLoop; // some connections eLoop.exec(); } } }
then you have:
DataRequester dataReq; QtConcurrent::run(std::bind(DataRequester::calculateData,&dataReq));
Am I close?
if so, all the slots will be called in the same thread that called the constructor of the object -
Hi,
I have found my problem. In fact I'm using a special class (that I have not implemented) to execute my code through QtConcurrent. I have the source code of this class in front of me... and... it launches a QEventLoop that excludes user events! This is the source of my problem!@VRonin, it's you that gave me the solution. By asking me how I'm starting the QThread, I suddenly realized that the problem might come from this class. Thanks.