Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. exec of dialog not return in multithreading environment

exec of dialog not return in multithreading environment

Scheduled Pinned Locked Moved Solved General and Desktop
multi-threadeventdeadlock
27 Posts 5 Posters 9.4k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T tmp15711
    17 Nov 2017, 10:57

    @kshegunov

    do work (in the worker thread) -> need data (from the worker thread to the UI) -> get data (in the UI thread) -> data obtained (from the UI to the worker thread) -> continue work with the data (in the worker thread).

    I think my approach indeed obeys the idea. The worker thread does some work first, then emits a signal requesting user input, and continues. The only difference is the worker thread doesn't have slots and event loops. If it had, then the GUI thread have to emit a signal for each request, and the threads will tightly coupled which I'd like to avoid.

    void requestShowDialog()

    This approach has a drawback, namely job cannot be called by the GUI thread. But I will admit that it is a good approach.

    This means very little as there are differences in how the UI is integrated with the system event loop and windowing system for each platform.

    Obviously, different system has different features. That is why I choose QT. Without declarations, it is resonable to assume the same appearances.

    So, is it a bug of QT?

    K Offline
    K Offline
    kshegunov
    Moderators
    wrote on 17 Nov 2017, 11:08 last edited by kshegunov
    #13

    @tmp15711 said in exec of dialog not return in multithreading environment:

    The only difference is the worker thread doesn't have slots and event loops.

    Thus it's not event driven and hence you need to resort to tricks to tie imperative code to event driven GUI code. The moment you need to block in the middle of your code to wait for something in the GUI to happen, is the moment you should realize you're doing something very odd or wrong.

    This approach has a drawback, namely job cannot be called by the GUI thread.

    The job can't be called from the GUI thread anyway, because of the Qt::BlockingQueuedConnection. If you call something with that flag from the GUI thread and the receiver is in the GUI thread (which it is) you'd get very simply a deadlock.

    Without declarations, it is resonable to assume the same appearances.

    Not when it comes to the internals. Something working on one platform and not on the other, doesn't mean it works in principle and there's a problem with the specific platform, quite the contrary it means it doesn't work in principle and by some chance it works on specific platforms.

    So, is it a bug of QT?

    No!

    Read and abide by the Qt Code of Conduct

    T 2 Replies Last reply 17 Nov 2017, 11:19
    3
    • K kshegunov
      17 Nov 2017, 11:08

      @tmp15711 said in exec of dialog not return in multithreading environment:

      The only difference is the worker thread doesn't have slots and event loops.

      Thus it's not event driven and hence you need to resort to tricks to tie imperative code to event driven GUI code. The moment you need to block in the middle of your code to wait for something in the GUI to happen, is the moment you should realize you're doing something very odd or wrong.

      This approach has a drawback, namely job cannot be called by the GUI thread.

      The job can't be called from the GUI thread anyway, because of the Qt::BlockingQueuedConnection. If you call something with that flag from the GUI thread and the receiver is in the GUI thread (which it is) you'd get very simply a deadlock.

      Without declarations, it is resonable to assume the same appearances.

      Not when it comes to the internals. Something working on one platform and not on the other, doesn't mean it works in principle and there's a problem with the specific platform, quite the contrary it means it doesn't work in principle and by some chance it works on specific platforms.

      So, is it a bug of QT?

      No!

      T Offline
      T Offline
      tmp15711
      wrote on 17 Nov 2017, 11:19 last edited by
      #14

      @kshegunov

      Not when it comes to the internals. Something working on one platform and not on the other, doesn't mean it works in principle and there's a problem with the specific platform, quite the contrary it means it doesn't work in principle and by some chance it works on specific platforms.

      I cannot agree. Maybe my approach is odd (and if it is, I'd like to admit), but if it is not forbidden anywhere in Qt's documents, it should work.
      In fact, the program is not really blocked. If you add a periodic timer, it works all the time. Why the timeout is responsed while exec does not return? Surprisingly.

      K 1 Reply Last reply 17 Nov 2017, 11:32
      0
      • S Offline
        S Offline
        SGaist
        Lifetime Qt Champion
        wrote on 17 Nov 2017, 11:23 last edited by
        #15

        Because exec spins a local event loop which will process events in the context of the dialog.

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        T 1 Reply Last reply 17 Nov 2017, 11:31
        1
        • K kshegunov
          17 Nov 2017, 11:08

          @tmp15711 said in exec of dialog not return in multithreading environment:

          The only difference is the worker thread doesn't have slots and event loops.

          Thus it's not event driven and hence you need to resort to tricks to tie imperative code to event driven GUI code. The moment you need to block in the middle of your code to wait for something in the GUI to happen, is the moment you should realize you're doing something very odd or wrong.

          This approach has a drawback, namely job cannot be called by the GUI thread.

          The job can't be called from the GUI thread anyway, because of the Qt::BlockingQueuedConnection. If you call something with that flag from the GUI thread and the receiver is in the GUI thread (which it is) you'd get very simply a deadlock.

          Without declarations, it is resonable to assume the same appearances.

          Not when it comes to the internals. Something working on one platform and not on the other, doesn't mean it works in principle and there's a problem with the specific platform, quite the contrary it means it doesn't work in principle and by some chance it works on specific platforms.

          So, is it a bug of QT?

          No!

          T Offline
          T Offline
          tmp15711
          wrote on 17 Nov 2017, 11:26 last edited by
          #16

          @kshegunov

          Thus it's not event driven

          In my opinion, event driven means one direction dependences, i.e. the slots know the signal. If the GUI thread has to response with signals, then it really knows the worker thread. And it should not.

          1 Reply Last reply
          0
          • S SGaist
            17 Nov 2017, 11:23

            Because exec spins a local event loop which will process events in the context of the dialog.

            T Offline
            T Offline
            tmp15711
            wrote on 17 Nov 2017, 11:31 last edited by
            #17

            @SGaist Yes, I know that. So? exec should not return when I closing the dialog?

            1 Reply Last reply
            0
            • T tmp15711
              17 Nov 2017, 11:19

              @kshegunov

              Not when it comes to the internals. Something working on one platform and not on the other, doesn't mean it works in principle and there's a problem with the specific platform, quite the contrary it means it doesn't work in principle and by some chance it works on specific platforms.

              I cannot agree. Maybe my approach is odd (and if it is, I'd like to admit), but if it is not forbidden anywhere in Qt's documents, it should work.
              In fact, the program is not really blocked. If you add a periodic timer, it works all the time. Why the timeout is responsed while exec does not return? Surprisingly.

              K Offline
              K Offline
              kshegunov
              Moderators
              wrote on 17 Nov 2017, 11:32 last edited by
              #18

              @tmp15711 said in exec of dialog not return in multithreading environment:

              I cannot agree.

              Let me put it in another way then. I'm a physicist, so I'll give you an example with a simple process:

              Suppose you claim that water boils at exactly 100 degrees centigrade, and you measure it 5 times and you confirm that supposition. Now suppose I decide to replicate your experiment but the atmospheric pressure in my lab is lower than in yours. I measure and find out that water boils at 95 degrees, instead of the 100 you claim. It's enough for me to show a measurement (assuming we all agree the measurements are correct) that contradicts your theory to disprove it. It's needed, formally speaking, for you to show an infinite amounts of measurements that support the theory to prove it.

              It's by this peculiarity of the scientific method that we learn and "prove" new things. So back to business, your code (which is user code) can't be claimed to work if it doesn't work at all times on all platforms, on the other hand it clearly does not work if it doesn't run even on one platform. And since we can say Qt's signal-slot mechanism and threading is mostly proven (in the sense of the countless test and programs that run it without issue), then the problem must be in the way you wrote the user code.

              Maybe my approach is odd (and if it is, I'd like to admit), but if it is not forbidden anywhere in Qt's documents, it should work.

              Assuming you implement it correctly, which you had not.

              In fact, the program is not really blocked. If you add a periodic timer, it works all the time. Why the timeout is responsed while exec does not return?

              See @SGaist's post.

              If the GUI thread has to response with signals, then it really knows the worker thread. And it should not.

              This is what event driven means. The GUI "notifies the interested parties" that something "interesting" has happened. Whether or not it knows about the workers is another matter that is connected to coupling, but lets not dig into it here. The "event driven" part is that the GUI does that notification at an unspecified time (from the viewpoint of the subscribers). It can be immediately, it can be an hour late, it may even not happen at all.

              Read and abide by the Qt Code of Conduct

              T J 2 Replies Last reply 17 Nov 2017, 11:43
              2
              • J Online
                J Online
                J.Hilk
                Moderators
                wrote on 17 Nov 2017, 11:42 last edited by J.Hilk
                #19

                @kshegunov thumbs up for a fellow physicist ;-)

                @tmp15711 I think you're approaching this from the wrong direction. QtConcurrent is meant more as an fire and forget type of thread:
                Something along the line of:

                Yo QtConcurrent, calculate Pi to 400 decimals while I watch this video

                I would recommend moving your whole stuff in its own class, and move that in a QThread object, that way you can easly react to and request Userinput, if you define suitable signals and slots.

                QThread & worker, general usage


                Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                Q: What's that?
                A: It's blue light.
                Q: What does it do?
                A: It turns blue.

                T 1 Reply Last reply 17 Nov 2017, 11:58
                1
                • K kshegunov
                  17 Nov 2017, 11:32

                  @tmp15711 said in exec of dialog not return in multithreading environment:

                  I cannot agree.

                  Let me put it in another way then. I'm a physicist, so I'll give you an example with a simple process:

                  Suppose you claim that water boils at exactly 100 degrees centigrade, and you measure it 5 times and you confirm that supposition. Now suppose I decide to replicate your experiment but the atmospheric pressure in my lab is lower than in yours. I measure and find out that water boils at 95 degrees, instead of the 100 you claim. It's enough for me to show a measurement (assuming we all agree the measurements are correct) that contradicts your theory to disprove it. It's needed, formally speaking, for you to show an infinite amounts of measurements that support the theory to prove it.

                  It's by this peculiarity of the scientific method that we learn and "prove" new things. So back to business, your code (which is user code) can't be claimed to work if it doesn't work at all times on all platforms, on the other hand it clearly does not work if it doesn't run even on one platform. And since we can say Qt's signal-slot mechanism and threading is mostly proven (in the sense of the countless test and programs that run it without issue), then the problem must be in the way you wrote the user code.

                  Maybe my approach is odd (and if it is, I'd like to admit), but if it is not forbidden anywhere in Qt's documents, it should work.

                  Assuming you implement it correctly, which you had not.

                  In fact, the program is not really blocked. If you add a periodic timer, it works all the time. Why the timeout is responsed while exec does not return?

                  See @SGaist's post.

                  If the GUI thread has to response with signals, then it really knows the worker thread. And it should not.

                  This is what event driven means. The GUI "notifies the interested parties" that something "interesting" has happened. Whether or not it knows about the workers is another matter that is connected to coupling, but lets not dig into it here. The "event driven" part is that the GUI does that notification at an unspecified time (from the viewpoint of the subscribers). It can be immediately, it can be an hour late, it may even not happen at all.

                  T Offline
                  T Offline
                  tmp15711
                  wrote on 17 Nov 2017, 11:43 last edited by
                  #20

                  @kshegunov Ok. Really, your words are powerful. Then, if my code is wrong, I want to know the key error, a formally logical analysis. For example, if we have a deadlock, we would say: oh, you try to lock a mutex that has been locked by some other thread which in turn tries to lock the mutex you have taken.

                  K 1 Reply Last reply 17 Nov 2017, 11:54
                  0
                  • K kshegunov
                    17 Nov 2017, 11:32

                    @tmp15711 said in exec of dialog not return in multithreading environment:

                    I cannot agree.

                    Let me put it in another way then. I'm a physicist, so I'll give you an example with a simple process:

                    Suppose you claim that water boils at exactly 100 degrees centigrade, and you measure it 5 times and you confirm that supposition. Now suppose I decide to replicate your experiment but the atmospheric pressure in my lab is lower than in yours. I measure and find out that water boils at 95 degrees, instead of the 100 you claim. It's enough for me to show a measurement (assuming we all agree the measurements are correct) that contradicts your theory to disprove it. It's needed, formally speaking, for you to show an infinite amounts of measurements that support the theory to prove it.

                    It's by this peculiarity of the scientific method that we learn and "prove" new things. So back to business, your code (which is user code) can't be claimed to work if it doesn't work at all times on all platforms, on the other hand it clearly does not work if it doesn't run even on one platform. And since we can say Qt's signal-slot mechanism and threading is mostly proven (in the sense of the countless test and programs that run it without issue), then the problem must be in the way you wrote the user code.

                    Maybe my approach is odd (and if it is, I'd like to admit), but if it is not forbidden anywhere in Qt's documents, it should work.

                    Assuming you implement it correctly, which you had not.

                    In fact, the program is not really blocked. If you add a periodic timer, it works all the time. Why the timeout is responsed while exec does not return?

                    See @SGaist's post.

                    If the GUI thread has to response with signals, then it really knows the worker thread. And it should not.

                    This is what event driven means. The GUI "notifies the interested parties" that something "interesting" has happened. Whether or not it knows about the workers is another matter that is connected to coupling, but lets not dig into it here. The "event driven" part is that the GUI does that notification at an unspecified time (from the viewpoint of the subscribers). It can be immediately, it can be an hour late, it may even not happen at all.

                    J Offline
                    J Offline
                    JonB
                    wrote on 17 Nov 2017, 11:44 last edited by JonB
                    #21

                    @kshegunov said in exec of dialog not return in multithreading environment:

                    I'm a physicist,

                    [ Ah! OT, sorry, but where can I post on this forum to ask you about my (layman's) theories on quantum mechanics? ;-) ]

                    1 Reply Last reply
                    0
                    • T tmp15711
                      17 Nov 2017, 11:43

                      @kshegunov Ok. Really, your words are powerful. Then, if my code is wrong, I want to know the key error, a formally logical analysis. For example, if we have a deadlock, we would say: oh, you try to lock a mutex that has been locked by some other thread which in turn tries to lock the mutex you have taken.

                      K Offline
                      K Offline
                      kshegunov
                      Moderators
                      wrote on 17 Nov 2017, 11:54 last edited by
                      #22

                      @tmp15711 said in exec of dialog not return in multithreading environment:

                      Then, if my code is wrong, I want to know the key error, a formally logical analysis

                      Okay, I'll bite. Since @SGaist duly noted that QDialog::exec spins the event loop of the GUI thread, which it most certainly does, if you use only:

                      QMetaObject::invokeMethod(this, "showDialog", Qt::BlockingQueuedConnection);
                      

                      That means that while you're waiting for input in the dialog in the background signals and slots are still fired. This implies also that your second thread calling the above function will cause the GUI to open a second dialog. Now to prevent this I've added a serialization primitive (the mutex) which ensures that only one of the worker threads can post the showDialog call to the UI event loop. When one of the workers finally continues, only then another worker can request a dialog to be shown.

                      where can I post on this forum to ask you about my (layman's) theories on quantum mechanics?

                      That'd be The Lounge, but don't hold your breath, no one really understands it (it's a math theory anyway).

                      Read and abide by the Qt Code of Conduct

                      T 1 Reply Last reply 17 Nov 2017, 12:04
                      0
                      • J J.Hilk
                        17 Nov 2017, 11:42

                        @kshegunov thumbs up for a fellow physicist ;-)

                        @tmp15711 I think you're approaching this from the wrong direction. QtConcurrent is meant more as an fire and forget type of thread:
                        Something along the line of:

                        Yo QtConcurrent, calculate Pi to 400 decimals while I watch this video

                        I would recommend moving your whole stuff in its own class, and move that in a QThread object, that way you can easly react to and request Userinput, if you define suitable signals and slots.

                        QThread & worker, general usage

                        T Offline
                        T Offline
                        tmp15711
                        wrote on 17 Nov 2017, 11:58 last edited by
                        #23

                        @J.Hilk Then what if QtConcurrent encounters a problem or meets an error? Shouldn't QtConcurrent ask for help and wait for a moment? If I can use Qt::BlockingQueuedConnection, why use slots? I don't need an event loop and slots are really cumbersome in this case.

                        K 1 Reply Last reply 17 Nov 2017, 11:59
                        0
                        • T tmp15711
                          17 Nov 2017, 11:58

                          @J.Hilk Then what if QtConcurrent encounters a problem or meets an error? Shouldn't QtConcurrent ask for help and wait for a moment? If I can use Qt::BlockingQueuedConnection, why use slots? I don't need an event loop and slots are really cumbersome in this case.

                          K Offline
                          K Offline
                          kshegunov
                          Moderators
                          wrote on 17 Nov 2017, 11:59 last edited by
                          #24

                          You can use the returned from QtConcurrent::run future (QFuture) to signal errors or return data that's been accumulated during the execution of the operation.

                          Read and abide by the Qt Code of Conduct

                          1 Reply Last reply
                          0
                          • K kshegunov
                            17 Nov 2017, 11:54

                            @tmp15711 said in exec of dialog not return in multithreading environment:

                            Then, if my code is wrong, I want to know the key error, a formally logical analysis

                            Okay, I'll bite. Since @SGaist duly noted that QDialog::exec spins the event loop of the GUI thread, which it most certainly does, if you use only:

                            QMetaObject::invokeMethod(this, "showDialog", Qt::BlockingQueuedConnection);
                            

                            That means that while you're waiting for input in the dialog in the background signals and slots are still fired. This implies also that your second thread calling the above function will cause the GUI to open a second dialog. Now to prevent this I've added a serialization primitive (the mutex) which ensures that only one of the worker threads can post the showDialog call to the UI event loop. When one of the workers finally continues, only then another worker can request a dialog to be shown.

                            where can I post on this forum to ask you about my (layman's) theories on quantum mechanics?

                            That'd be The Lounge, but don't hold your breath, no one really understands it (it's a math theory anyway).

                            T Offline
                            T Offline
                            tmp15711
                            wrote on 17 Nov 2017, 12:04 last edited by
                            #25

                            @kshegunov You are correct. I have tested. The mutex approach certaintly works. But why not mine, the event loop approach? I mean why exec doesn't return after the dialog is closed.

                            @kshegunov Error doesn't mean the threads have to exit. Or, maybe just a warning.

                            K 1 Reply Last reply 17 Nov 2017, 12:33
                            0
                            • T tmp15711
                              17 Nov 2017, 12:04

                              @kshegunov You are correct. I have tested. The mutex approach certaintly works. But why not mine, the event loop approach? I mean why exec doesn't return after the dialog is closed.

                              @kshegunov Error doesn't mean the threads have to exit. Or, maybe just a warning.

                              K Offline
                              K Offline
                              kshegunov
                              Moderators
                              wrote on 17 Nov 2017, 12:33 last edited by kshegunov
                              #26

                              @tmp15711 said in exec of dialog not return in multithreading environment:

                              But why not mine, the event loop approach? I mean why exec doesn't return after the dialog is closed.

                              Because both of the slots are executed and you have interleaved execution, due to the fact that exec() will spin the even loop. Think of it like this:

                              1. Thread 1 calls QDialog::exec this causes the even loop to continue receiving events
                              2. Thread 2 calls QMetaObject::invokeMethod(this, "showDialog", Qt::BlockingQueuedConnection); which posts an event to the event loop. Due to 1) that slot starts to execute and a second dialog and a nested QDialog::exec is called.

                              That's why the mutex works, it ensures that only one QDialog::exec is called at any one point by serializing the calls to QMetaObject::invokeMethod.

                              Error doesn't mean the threads have to exit. Or, maybe just a warning.

                              Then consider using class deriving from QRunnable and QObject to represent your job, and to so you can have signals in it to tell the GUI some error/warning has occurred. Alternatively, I'd suggest following @J-Hilk's advice and just switching to plain old QThread classes with worker objects.

                              Read and abide by the Qt Code of Conduct

                              T 1 Reply Last reply 17 Nov 2017, 13:29
                              2
                              • K kshegunov
                                17 Nov 2017, 12:33

                                @tmp15711 said in exec of dialog not return in multithreading environment:

                                But why not mine, the event loop approach? I mean why exec doesn't return after the dialog is closed.

                                Because both of the slots are executed and you have interleaved execution, due to the fact that exec() will spin the even loop. Think of it like this:

                                1. Thread 1 calls QDialog::exec this causes the even loop to continue receiving events
                                2. Thread 2 calls QMetaObject::invokeMethod(this, "showDialog", Qt::BlockingQueuedConnection); which posts an event to the event loop. Due to 1) that slot starts to execute and a second dialog and a nested QDialog::exec is called.

                                That's why the mutex works, it ensures that only one QDialog::exec is called at any one point by serializing the calls to QMetaObject::invokeMethod.

                                Error doesn't mean the threads have to exit. Or, maybe just a warning.

                                Then consider using class deriving from QRunnable and QObject to represent your job, and to so you can have signals in it to tell the GUI some error/warning has occurred. Alternatively, I'd suggest following @J-Hilk's advice and just switching to plain old QThread classes with worker objects.

                                T Offline
                                T Offline
                                tmp15711
                                wrote on 17 Nov 2017, 13:29 last edited by
                                #27

                                @kshegunov Thanks. I can reproduce the same behavior with a single thread.

                                #include <QtCore>
                                
                                struct Object: QObject{
                                	Q_OBJECT
                                public slots:
                                	void foo(){
                                		qDebug() << __LINE__;
                                		while(entered) qApp->processEvents();
                                
                                		qDebug() << __LINE__;
                                		QEventLoop loop;
                                		QTimer::singleShot(1000, &loop, SLOT(quit()));
                                		entered = true;
                                		loop.exec();
                                		entered = false;
                                		qDebug() << __LINE__;
                                	}
                                
                                private:
                                	bool entered = false;
                                };
                                
                                int main(int argc, char *argv[])
                                {
                                	QCoreApplication a(argc, argv);
                                	Object w;
                                
                                	QTimer::singleShot(0, &w, SLOT(foo()));
                                	QTimer::singleShot(0, &w, SLOT(foo()));
                                	QTimer::singleShot(3000, &a, SLOT(quit()));
                                
                                	a.exec();
                                	qDebug() << __LINE__;
                                }
                                
                                #include "main.moc"
                                

                                In fact, it has nothing to do with multi-threads. I have never studied Qt source code. It seems exec will not return before all slots finish. So, the code actually creates a dead lock.

                                1 Reply Last reply
                                0

                                22/27

                                17 Nov 2017, 11:54

                                • Login

                                • Login or register to search.
                                22 out of 27
                                • First post
                                  22/27
                                  Last post
                                0
                                • Categories
                                • Recent
                                • Tags
                                • Popular
                                • Users
                                • Groups
                                • Search
                                • Get Qt Extensions
                                • Unsolved