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. Correct way to interrupt long running calculation inside a slot in another thread?
Forum Updated to NodeBB v4.3 + New Features

Correct way to interrupt long running calculation inside a slot in another thread?

Scheduled Pinned Locked Moved Unsolved General and Desktop
21 Posts 6 Posters 3.2k Views 1 Watching
  • 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.
  • O ollarch

    @JonB I understand it, I'm only curious about it. I thought that the assignment was an atomic operation and so there was no problem. On non atomic assignments, yes, a Mutex is needed.
    Thanks for explanation.

    jsulmJ Offline
    jsulmJ Offline
    jsulm
    Lifetime Qt Champion
    wrote on last edited by
    #9

    @ollarch Assignment is not atomic. For basic types like int you can make it atomic, but it is up to you as developer.

    https://forum.qt.io/topic/113070/qt-code-of-conduct

    CJhaC 1 Reply Last reply
    4
    • jsulmJ jsulm

      @ollarch Assignment is not atomic. For basic types like int you can make it atomic, but it is up to you as developer.

      CJhaC Offline
      CJhaC Offline
      CJha
      wrote on last edited by
      #10

      @jsulm Hi, by just using std::atomic<bool> abortCalculation should be enough right? Then I can access this variable from any thread without needing to use QMutex or Signal-Slot connection?

      jsulmJ 1 Reply Last reply
      0
      • CJhaC Offline
        CJhaC Offline
        CJha
        wrote on last edited by
        #11

        @Christian-Ehrlicher Wouldn't Qt::QueuedConnection wait for my doCalculation() slot to finish before invoking the stopCalculation() if I am calling both of these slots from Master?

        JonBJ 1 Reply Last reply
        1
        • CJhaC CJha

          @Christian-Ehrlicher Wouldn't Qt::QueuedConnection wait for my doCalculation() slot to finish before invoking the stopCalculation() if I am calling both of these slots from Master?

          JonBJ Online
          JonBJ Online
          JonB
          wrote on last edited by JonB
          #12

          @CJha
          If you are waiting for doCalculation() to finish before letting stopCalculation() run, it will never abort the loop.....

          CJhaC 1 Reply Last reply
          1
          • JonBJ JonB

            @CJha
            If you are waiting for doCalculation() to finish before letting stopCalculation() run, it will never abort the loop.....

            CJhaC Offline
            CJhaC Offline
            CJha
            wrote on last edited by
            #13

            @JonB Thanks, but my question is will the call to stopCalculation() wait for doCalculation() to finish if I am using Qt::QueuedConnection and calling these slots from Master?

            J.HilkJ 1 Reply Last reply
            0
            • CJhaC CJha

              @JonB Thanks, but my question is will the call to stopCalculation() wait for doCalculation() to finish if I am using Qt::QueuedConnection and calling these slots from Master?

              J.HilkJ Offline
              J.HilkJ Offline
              J.Hilk
              Moderators
              wrote on last edited by
              #14

              @CJha no, the slot call would be invoked when the eventloop starts running again, and it won't as long as your function did not return.

              The only way would be with a forced direct connection, than the slot is executed in the other thread. But you will have to mutex lock inside the slot than.


              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.

              CJhaC 1 Reply Last reply
              1
              • J.HilkJ J.Hilk

                @CJha no, the slot call would be invoked when the eventloop starts running again, and it won't as long as your function did not return.

                The only way would be with a forced direct connection, than the slot is executed in the other thread. But you will have to mutex lock inside the slot than.

                CJhaC Offline
                CJhaC Offline
                CJha
                wrote on last edited by
                #15

                @J-Hilk Thanks a lot for clarifying this, I working on a solution now but it takes a long time to make the code and I was constantly wondering about this till now.

                1 Reply Last reply
                0
                • CJhaC CJha

                  @jsulm Hi, by just using std::atomic<bool> abortCalculation should be enough right? Then I can access this variable from any thread without needing to use QMutex or Signal-Slot connection?

                  jsulmJ Offline
                  jsulmJ Offline
                  jsulm
                  Lifetime Qt Champion
                  wrote on last edited by
                  #16

                  @CJha said in Correct way to interrupt long running calculation inside a slot in another thread?:

                  std::atomic<bool> abortCalculation

                  Yes, this should do it

                  https://forum.qt.io/topic/113070/qt-code-of-conduct

                  1 Reply Last reply
                  3
                  • CJhaC Offline
                    CJhaC Offline
                    CJha
                    wrote on last edited by CJha
                    #17

                    Hi everyone, currently I am working on a solution to check which method works best. But since Master is a huge class it is taking me some time to finish it for final testing. I have changed my method, now I am using a local QEventLoop in Master to wait for an aborted() signal from my Worker object.

                    The code outline for Master to control Worker is as follows:

                    // Masters slot controlling worker's behaviour
                    // This slot is called by a QPushButton in GUI
                    void Master::startCalculation()
                    {
                        if(workerRunning) // std::atomic<bool> workerRunning; - defined in master.h
                        {
                            // If yes, start an event loop and wait for aborted signal
                            QEventLoop loop;
                            connect(workerObject, &Worker::aborted, &loop, &QEventLoop::quit);
                            workerObject->abortCalculation = true;
                            loop.exec();
                        }
                        // now start new calculation
                        workerObject->doCalculation(dataVector); // dataVector is QVector<double>
                    }
                    

                    The Worker code is changed now:

                    // a long running calculation inside a slot:
                    void Worker::doCalculation(const QVector<double>& vec)
                    {
                        // Tell master that worker is starting
                        masterObject->workerRunning = true;
                    
                        // Start the calculation part
                        for(int ii = 0; ii < vec.length(); ++ii)
                        {
                            if(abortCalculation){ // std::atomic<bool> abortCalculation; - defined in worker.h
                                emit aborted();
                                return;
                            }
                            else
                            {
                                // Do the calculation
                                // Each iteration takes around 0.5 ms
                                // Total: 1K to 1000K iteration in each call
                            }
                        }
                    
                        // Tell master worker has stopped
                        masterObject->workerRunning = false;
                    }
                    

                    To me it appears that the above solution will be the best one. But I still have one small doubt: Does starting a new QEventLoop inside a slot of main GUI thread and waiting for it to quit() stop the event loop of main GUI thread? As far as my understanding goes, I think that will be the case, if so, is there a way I can wait for aborted() signal inside a main GUI slot without blocking the entire main GUI thread?

                    JonBJ 1 Reply Last reply
                    0
                    • CJhaC CJha

                      Hi everyone, currently I am working on a solution to check which method works best. But since Master is a huge class it is taking me some time to finish it for final testing. I have changed my method, now I am using a local QEventLoop in Master to wait for an aborted() signal from my Worker object.

                      The code outline for Master to control Worker is as follows:

                      // Masters slot controlling worker's behaviour
                      // This slot is called by a QPushButton in GUI
                      void Master::startCalculation()
                      {
                          if(workerRunning) // std::atomic<bool> workerRunning; - defined in master.h
                          {
                              // If yes, start an event loop and wait for aborted signal
                              QEventLoop loop;
                              connect(workerObject, &Worker::aborted, &loop, &QEventLoop::quit);
                              workerObject->abortCalculation = true;
                              loop.exec();
                          }
                          // now start new calculation
                          workerObject->doCalculation(dataVector); // dataVector is QVector<double>
                      }
                      

                      The Worker code is changed now:

                      // a long running calculation inside a slot:
                      void Worker::doCalculation(const QVector<double>& vec)
                      {
                          // Tell master that worker is starting
                          masterObject->workerRunning = true;
                      
                          // Start the calculation part
                          for(int ii = 0; ii < vec.length(); ++ii)
                          {
                              if(abortCalculation){ // std::atomic<bool> abortCalculation; - defined in worker.h
                                  emit aborted();
                                  return;
                              }
                              else
                              {
                                  // Do the calculation
                                  // Each iteration takes around 0.5 ms
                                  // Total: 1K to 1000K iteration in each call
                              }
                          }
                      
                          // Tell master worker has stopped
                          masterObject->workerRunning = false;
                      }
                      

                      To me it appears that the above solution will be the best one. But I still have one small doubt: Does starting a new QEventLoop inside a slot of main GUI thread and waiting for it to quit() stop the event loop of main GUI thread? As far as my understanding goes, I think that will be the case, if so, is there a way I can wait for aborted() signal inside a main GUI slot without blocking the entire main GUI thread?

                      JonBJ Online
                      JonBJ Online
                      JonB
                      wrote on last edited by JonB
                      #18

                      @CJha
                      If workerRunning is true your startCalculation() blocks and waits until Worker is aborted, and only then sets off doCalculation(). And if Worker does not call aborted() that will be when Hell freezes over. Is this really your intended architecture?? I'm lost with what you are up to....

                      CJhaC 1 Reply Last reply
                      2
                      • JonBJ JonB

                        @CJha
                        If workerRunning is true your startCalculation() blocks and waits until Worker is aborted, and only then sets off doCalculation(). And if Worker does not call aborted() that will be when Hell freezes over. Is this really your intended architecture?? I'm lost with what you are up to....

                        CJhaC Offline
                        CJhaC Offline
                        CJha
                        wrote on last edited by
                        #19

                        @JonB Thanks, yes this is my intended architecture. In my Worker I am generating a line plot on a QImage which it sends to Master. The Master is a subclassed QWidget where I display this QImage as a plot in a certain area. My architecture is this way because I have enabled multiple interactions with the plot in Master using the mouse and keyboard interactions, such that users can zoom and scroll. However, since the data to be plotted is quite big I need to have a way to abort the generation of QImage inside Worker otherwise the zoom and scroll behaviour will lag enormously.

                        JonBJ 1 Reply Last reply
                        0
                        • CJhaC CJha

                          @JonB Thanks, yes this is my intended architecture. In my Worker I am generating a line plot on a QImage which it sends to Master. The Master is a subclassed QWidget where I display this QImage as a plot in a certain area. My architecture is this way because I have enabled multiple interactions with the plot in Master using the mouse and keyboard interactions, such that users can zoom and scroll. However, since the data to be plotted is quite big I need to have a way to abort the generation of QImage inside Worker otherwise the zoom and scroll behaviour will lag enormously.

                          JonBJ Online
                          JonBJ Online
                          JonB
                          wrote on last edited by
                          #20

                          @CJha
                          Doesn't sound right to me. If your Worker finishes without going emit aborted(); you never exit your loop.exec() and are stuck there, like I said, till The Universe comes to an end.

                          I don't understand, so I will just say this. I have a funny feeling that what you want is for the main thread to check for worker aborted intermittently, while remaining UI-responsive and checking for aborted, which requires signal processing. If that is so you have two possible approaches:

                          • Call processEvents() each time round its loop. Signals will be processed at that point.
                          • Change so you do not have a tight loop around each element in the vector. Instead have a QTimer() and on each timeout process some number of the remaining items in the vector, noting where you got to.

                          I leave it to you....

                          1 Reply Last reply
                          1
                          • Christian EhrlicherC Online
                            Christian EhrlicherC Online
                            Christian Ehrlicher
                            Lifetime Qt Champion
                            wrote on last edited by
                            #21

                            You can use your first example, an atomic bool and check this in every n'th iteration. Everything else is not needed and will not help.
                            You can also avoid the atomic bool and use the QThread built-in QThread::requestInterruption() and check for QThread::isInterruptionRequested() once in a while in your loop.

                            Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                            Visit the Qt Academy at https://academy.qt.io/catalog

                            1 Reply Last reply
                            3

                            • Login

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