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. QThread not exiting when signalled using SLOT(quit())
QtWS25 Last Chance

QThread not exiting when signalled using SLOT(quit())

Scheduled Pinned Locked Moved General and Desktop
qthreadqthreadsthreadsignals & slotssignals&slots
11 Posts 3 Posters 6.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.
  • zzajZ Offline
    zzajZ Offline
    zzaj
    wrote on last edited by zzaj
    #1

    I'm fairly new to programming with Qt and threading, and i'm trying to write a simple opencv program that uses a thread to connect to a VideoCapture object in order to keep the main GUI responsive. The reason i'm doing this is that i'm connecting to IP cameras and if given the wrong IP address the function to open the capture object will often just time out instead of returning, so I want to handle this using a thread.

    The issue i'm having is that when the method does return and emit a finished signal, which i've connected to the thread's quit() slot, it doesnt actually quit and the program just hangs. You can see my code below:

    bool captureHandler::newConnection(cv::VideoCapture &capture, QString address)
    {
        QThread* thread = new QThread;
        streamConnector* c = new streamConnector(capture, address);
    
        c->moveToThread(thread);
    
        connect(thread, SIGNAL(started()), c, SLOT(process()));
        connect(c, SIGNAL(finished()), thread, SLOT(quit())); //Does not work?
        connect(c, SIGNAL(finished()), c, SLOT(deleteLater()));
        connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
        thread->start();
        thread->wait();
    
        //code never gets here
        if(capture.isOpened()) {
            return true;
        } else {
            return false;
        }
    }
    

    Note: I call wait here because the next step in the main thread is to try and get an image from the capture object, so I need this method to return before continuing. The main purpose of this thread is to keep a responsive GUI while attempting to connect, I know that I am causing the main thread to wait.

    And the relevant code from the streamConnector class' process method is simply:

     capture->open(address.toStdString());
    ...
    emit finished();
    

    It is the call to open() here that sometimes times out using an IP.

    I have tested that the finished() signal is being emitting by connecting a slot which outputs some text to console, so I can confirm this works. But why does the thread not quit and hold up the entire program?

    As a side question, I want the main program to wait for this thread to finish or to timeout after 5 seconds. I have been substituting in wait(6000) but this will wait for 6 seconds regardless of the thread's success. Is it possible to use some sort of OR condition here?

    Thanks for your help

    1 Reply Last reply
    0
    • kshegunovK Offline
      kshegunovK Offline
      kshegunov
      Moderators
      wrote on last edited by kshegunov
      #2

      @zzaj said:

      thread->start();
      thread->wait();
      

      You start the thread and then block the main thread to wait for it? This doesn't make much sense, as the main thread will simply infinitely wait for the worker to finish. And if it doesn't, well you have a hanging program.

      Read and abide by the Qt Code of Conduct

      zzajZ 1 Reply Last reply
      0
      • kshegunovK kshegunov

        @zzaj said:

        thread->start();
        thread->wait();
        

        You start the thread and then block the main thread to wait for it? This doesn't make much sense, as the main thread will simply infinitely wait for the worker to finish. And if it doesn't, well you have a hanging program.

        zzajZ Offline
        zzajZ Offline
        zzaj
        wrote on last edited by
        #3

        @kshegunov

        I need to wait as the next step in the main thread is to try and capture an image from the VideoCapture object which will fail unless the connection is opened ie the thread is finished. I realise this kind of defeats the purpose, but using a thread enables me to have a responsive gui.

        If you have an alternative solution I would love to hear it. If not, can you answer either of the questions I asked? Why the quit() does not work or how to wait for thread completion OR ~6 seconds

        kshegunovK 1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          Hi and welcome to devnet,

          You're blocking your main thread's execution right after starting your thread when calling wait.

          Do you want to wait for the connection to happened before calling capture.isOpened() ?

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

          zzajZ 1 Reply Last reply
          0
          • zzajZ zzaj

            @kshegunov

            I need to wait as the next step in the main thread is to try and capture an image from the VideoCapture object which will fail unless the connection is opened ie the thread is finished. I realise this kind of defeats the purpose, but using a thread enables me to have a responsive gui.

            If you have an alternative solution I would love to hear it. If not, can you answer either of the questions I asked? Why the quit() does not work or how to wait for thread completion OR ~6 seconds

            kshegunovK Offline
            kshegunovK Offline
            kshegunov
            Moderators
            wrote on last edited by kshegunov
            #5

            @zzaj
            When you call wait() on the thread object, as already noted you're blocking the main thread's event loop. So when you emit the streamConnector::finished signal from the worker object, the thread object is posted an event that the quit slot should be called. The problem is that without having an event loop running in the main thread this event will not be processed, until the main thread unblocks (i.e. returns from wait()). This is because the thread affinity of your QThread instance is actually the main thread.

            If you need to do something and then wait for it (blocking the main thread) I suggest not using threads at all.

            Kind regards.

            Read and abide by the Qt Code of Conduct

            zzajZ 1 Reply Last reply
            0
            • SGaistS SGaist

              Hi and welcome to devnet,

              You're blocking your main thread's execution right after starting your thread when calling wait.

              Do you want to wait for the connection to happened before calling capture.isOpened() ?

              zzajZ Offline
              zzajZ Offline
              zzaj
              wrote on last edited by
              #6

              @SGaist

              Hi, and thanks.

              See my reply above (I've also edited the post for clarity). The next step in the main thread is to attempt to get an image so I need this method to return either true or false before continuing. I'm aware that the thread waits on this thread to end, that is the intended functionality. My issue is that it is not closing and hitting the capture.isOpen() despite a successful connection and finished() signal.

              1 Reply Last reply
              0
              • SGaistS Offline
                SGaistS Offline
                SGaist
                Lifetime Qt Champion
                wrote on last edited by
                #7

                To add to @kshegunov, if it's something that should be called after your worker object's work is done, then use a slot connected to your finished signal.

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

                1 Reply Last reply
                1
                • kshegunovK kshegunov

                  @zzaj
                  When you call wait() on the thread object, as already noted you're blocking the main thread's event loop. So when you emit the streamConnector::finished signal from the worker object, the thread object is posted an event that the quit slot should be called. The problem is that without having an event loop running in the main thread this event will not be processed, until the main thread unblocks (i.e. returns from wait()). This is because the thread affinity of your QThread instance is actually the main thread.

                  If you need to do something and then wait for it (blocking the main thread) I suggest not using threads at all.

                  Kind regards.

                  zzajZ Offline
                  zzajZ Offline
                  zzaj
                  wrote on last edited by
                  #8

                  @kshegunov
                  Thanks, that makes since. i've done a bit of reading on thread affinity now.

                  But I cannot see an alternative solution here. I need the main program to wait for a connection, and I need it to timeout after a set time or after completion. I also need the main gui to be responsive during this time. None of which I can achieve by running the capture->open(address) method during the main thread.

                  By using wait(6000) this program operates as I want it to, however it is forced to wait 6 seconds regardless of success or failure. Obviously this is not ideal, i'm looking for the correct way to achieve what I want.

                  kshegunovK 1 Reply Last reply
                  0
                  • zzajZ zzaj

                    @kshegunov
                    Thanks, that makes since. i've done a bit of reading on thread affinity now.

                    But I cannot see an alternative solution here. I need the main program to wait for a connection, and I need it to timeout after a set time or after completion. I also need the main gui to be responsive during this time. None of which I can achieve by running the capture->open(address) method during the main thread.

                    By using wait(6000) this program operates as I want it to, however it is forced to wait 6 seconds regardless of success or failure. Obviously this is not ideal, i'm looking for the correct way to achieve what I want.

                    kshegunovK Offline
                    kshegunovK Offline
                    kshegunov
                    Moderators
                    wrote on last edited by kshegunov
                    #9

                    @zzaj
                    See @SGaist's suggestion. You can fiddle a bit with signals and slots, but it should be pretty simple to implement.
                    You start your thread as you're doing now, but do not call wait(). Then in the worker object emit a signal to tell your thread that you have a valid connection, and in the slot that is connected to that signal put the rest of your code. It would look something like this:

                    void streamConnector::process()
                    {
                        capture->open(address.toStdString());
                        // Do some stuff 
                        if (capture->isOpened())
                            emit captureOpened();
                    
                        emit finished();
                    }   
                    

                    And you simply subscribe to the captureOpened() signal and do whatever you wish with your new and valid connection.

                    Now to handle timeouts, the slot that handles captureOpened() can set an internal boolean e.g. bool started. And you can start a one shot timer (after starting the worker thread) and connect the timer's timeout() signal to another slot that checks if started is true or false. This way you'll know whether your streamConnector::process() should be thought as timed-out.

                    Read and abide by the Qt Code of Conduct

                    zzajZ 1 Reply Last reply
                    2
                    • kshegunovK kshegunov

                      @zzaj
                      See @SGaist's suggestion. You can fiddle a bit with signals and slots, but it should be pretty simple to implement.
                      You start your thread as you're doing now, but do not call wait(). Then in the worker object emit a signal to tell your thread that you have a valid connection, and in the slot that is connected to that signal put the rest of your code. It would look something like this:

                      void streamConnector::process()
                      {
                          capture->open(address.toStdString());
                          // Do some stuff 
                          if (capture->isOpened())
                              emit captureOpened();
                      
                          emit finished();
                      }   
                      

                      And you simply subscribe to the captureOpened() signal and do whatever you wish with your new and valid connection.

                      Now to handle timeouts, the slot that handles captureOpened() can set an internal boolean e.g. bool started. And you can start a one shot timer (after starting the worker thread) and connect the timer's timeout() signal to another slot that checks if started is true or false. This way you'll know whether your streamConnector::process() should be thought as timed-out.

                      zzajZ Offline
                      zzajZ Offline
                      zzaj
                      wrote on last edited by
                      #10

                      @kshegunov
                      Thanks :) Thats very helpful.

                      kshegunovK 1 Reply Last reply
                      0
                      • zzajZ zzaj

                        @kshegunov
                        Thanks :) Thats very helpful.

                        kshegunovK Offline
                        kshegunovK Offline
                        kshegunov
                        Moderators
                        wrote on last edited by
                        #11

                        @zzaj
                        No problem. Good luck with your project!!

                        Read and abide by the Qt Code of Conduct

                        1 Reply Last reply
                        0

                        • Login

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