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. Why QThread::wait() never returns after invoked QThread::quit()?
Forum Update on Monday, May 27th 2025

Why QThread::wait() never returns after invoked QThread::quit()?

Scheduled Pinned Locked Moved Solved General and Desktop
qthreadthreadwaitquitdeadlock
8 Posts 2 Posters 6.3k 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.
  • F Offline
    F Offline
    Feuerteufel
    wrote on last edited by
    #1

    I have a problem, that QThread never returns from wait().
    The scenario contains 2 additional threads (QThread and std::thread) besides the main execution thread. Let's call the QThread Q, the std::thread T and the main thread M.
    In M I create Q, the Receiver-object R "living" in Q and the Sender-object S. Also a std::thread T is created executing a bunch if emits with S.

    class Sender : public QObject
    {
      Q_OBJECT;
    public:
      std::vector<int> m_Sent;
    
      Sender()
      {
      }
    
    public slots:
    signals:
      void signal(int i);
    
    public:
      void send(int i)
      {
        m_Sent.emplace_back(i);
        emit signal(i);
      }
    };
    
    
    class Receiver : public QObject
    {
      Q_OBJECT;
    public:
      std::vector<int> m_Received;
    
      Receiver()
      {
      }
    
      void Connect(Sender* s)
      {
        connect(s, &Sender::signal, this, &Receiver::slot, Qt::QueuedConnection);
      }
    
      void Disconnect(Sender* s)
      {
        disconnect(s, &Sender::signal, this, &Receiver::slot);
      }
    
    public slots:
      void slot(int i)
      {
        m_Received.emplace_back(i);
      }
    
    };
    
    void main(int argc, char** argv)
    {
      QApplication app(argc, argv);
      qint64 random_seed = QDateTime::currentMSecsSinceEpoch();
      std::cout << "Setting random seed " << random_seed << "\n";
      std::srand(random_seed);
      std::unique_ptr<Receiver> R(new Receiver);
      std::unique_ptr<Sender> S(new Sender);
      auto actions = [&S]() {
        int i = 0;
        std::chrono::steady_clock::time_point current =
                std::chrono::steady_clock::now();
        std::chrono::steady_clock::time_point finish =
                current + std::chrono::milliseconds(100);
        while (current < finish)
        {
          std::this_thread::sleep_for(std::chrono::microseconds(std::rand()%1000));
          S->send(i++);
          std::this_thread::sleep_for(std::chrono::microseconds(std::rand()%1000));
          S->send(i++);
          std::this_thread::sleep_for(std::chrono::microseconds(std::rand()%1000));
          S->send(i++);
          std::this_thread::sleep_for(std::chrono::microseconds(std::rand()%1000));
          S->send(i++);
          std::this_thread::sleep_until(current + std::chrono::milliseconds(17));
          current = std::chrono::steady_clock::now();
        }
      };
    
      std::unique_ptr<QThread> Q(new QThread());
      R->moveToThread(Q.get());
      R->Connect(S.get());
      Q->start();
      std::thread T(actions);
      T.join();
      QMetaObject::invokeMethod(Q.get(), "quit", Qt::QueuedConnection);
      Q->wait();// waits forever
    
      std::cout << "Sent:     ";
      for(auto v : S->m_Sent)
      {
        std::cout << v << " ";
      }
      std::cout << std::endl;
      std::cout << "Received: ";
      for(auto v : R->m_Received)
      {
        std::cout << v << " ";
      }
      std::cout << std::endl;
    }
    

    I'm working on Windows with VS2013 and Qt 5.5.1. While debugging I went through all emits so all should be inserted to event loop in Q. Also I tried to use a BlockingQueuedConnection for the invoked quit() and removed the wait() but then I got a Qt-warning/error of a detected Deadlock, but I don't use any locks, so seems to be some Qt-internal stuff I have no insight so far. Thanks for some enlightment on the problem ;-)

    kshegunovK 1 Reply Last reply
    0
    • F Feuerteufel

      I have a problem, that QThread never returns from wait().
      The scenario contains 2 additional threads (QThread and std::thread) besides the main execution thread. Let's call the QThread Q, the std::thread T and the main thread M.
      In M I create Q, the Receiver-object R "living" in Q and the Sender-object S. Also a std::thread T is created executing a bunch if emits with S.

      class Sender : public QObject
      {
        Q_OBJECT;
      public:
        std::vector<int> m_Sent;
      
        Sender()
        {
        }
      
      public slots:
      signals:
        void signal(int i);
      
      public:
        void send(int i)
        {
          m_Sent.emplace_back(i);
          emit signal(i);
        }
      };
      
      
      class Receiver : public QObject
      {
        Q_OBJECT;
      public:
        std::vector<int> m_Received;
      
        Receiver()
        {
        }
      
        void Connect(Sender* s)
        {
          connect(s, &Sender::signal, this, &Receiver::slot, Qt::QueuedConnection);
        }
      
        void Disconnect(Sender* s)
        {
          disconnect(s, &Sender::signal, this, &Receiver::slot);
        }
      
      public slots:
        void slot(int i)
        {
          m_Received.emplace_back(i);
        }
      
      };
      
      void main(int argc, char** argv)
      {
        QApplication app(argc, argv);
        qint64 random_seed = QDateTime::currentMSecsSinceEpoch();
        std::cout << "Setting random seed " << random_seed << "\n";
        std::srand(random_seed);
        std::unique_ptr<Receiver> R(new Receiver);
        std::unique_ptr<Sender> S(new Sender);
        auto actions = [&S]() {
          int i = 0;
          std::chrono::steady_clock::time_point current =
                  std::chrono::steady_clock::now();
          std::chrono::steady_clock::time_point finish =
                  current + std::chrono::milliseconds(100);
          while (current < finish)
          {
            std::this_thread::sleep_for(std::chrono::microseconds(std::rand()%1000));
            S->send(i++);
            std::this_thread::sleep_for(std::chrono::microseconds(std::rand()%1000));
            S->send(i++);
            std::this_thread::sleep_for(std::chrono::microseconds(std::rand()%1000));
            S->send(i++);
            std::this_thread::sleep_for(std::chrono::microseconds(std::rand()%1000));
            S->send(i++);
            std::this_thread::sleep_until(current + std::chrono::milliseconds(17));
            current = std::chrono::steady_clock::now();
          }
        };
      
        std::unique_ptr<QThread> Q(new QThread());
        R->moveToThread(Q.get());
        R->Connect(S.get());
        Q->start();
        std::thread T(actions);
        T.join();
        QMetaObject::invokeMethod(Q.get(), "quit", Qt::QueuedConnection);
        Q->wait();// waits forever
      
        std::cout << "Sent:     ";
        for(auto v : S->m_Sent)
        {
          std::cout << v << " ";
        }
        std::cout << std::endl;
        std::cout << "Received: ";
        for(auto v : R->m_Received)
        {
          std::cout << v << " ";
        }
        std::cout << std::endl;
      }
      

      I'm working on Windows with VS2013 and Qt 5.5.1. While debugging I went through all emits so all should be inserted to event loop in Q. Also I tried to use a BlockingQueuedConnection for the invoked quit() and removed the wait() but then I got a Qt-warning/error of a detected Deadlock, but I don't use any locks, so seems to be some Qt-internal stuff I have no insight so far. Thanks for some enlightment on the problem ;-)

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

      Sweet Mary ... that's one big pile of a mess ... I had to read it 3 times to get what's happening.
      Here:

      QMetaObject::invokeMethod(Q.get(), "quit", Qt::QueuedConnection);
      

      This posts an event to the QThread's event loop (which is the main event loop), so the event is never processed as you're blocking the main event loop by calling QThread::wait().

      Q.get()->quit(); 
      

      should work just fine.

      Read and abide by the Qt Code of Conduct

      1 Reply Last reply
      1
      • F Offline
        F Offline
        Feuerteufel
        wrote on last edited by
        #3

        There is no main event loop and that is intended. There is only one event loop in the thread handled by QThread Q. I tried to call just Q.get()->quit() but than it happens that not all sent events are really handled. I need a way to put the quit() at the end of the event loop in Q and afterwards waiting in the main thread that Q is finished. But thanks for your response.

        1 Reply Last reply
        0
        • F Offline
          F Offline
          Feuerteufel
          wrote on last edited by
          #4

          Still no solution? Doesn't Qt provide a way to insert kind of quit statement in the eventloop of the thread (not the main eventloop).

          kshegunovK 1 Reply Last reply
          0
          • F Feuerteufel

            Still no solution? Doesn't Qt provide a way to insert kind of quit statement in the eventloop of the thread (not the main eventloop).

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

            There is no main event loop and that is intended.

            Sure there is, as long as you have a QApplication object, you have a main event loop, you just don't spin it.

            Still no solution? Doesn't Qt provide a way to insert kind of quit statement in the eventloop of the thread (not the main eventloop).

            Not really, no, and there's no need too. You have that problem because of your mixing of event-driven and iteration based threads, but you can easily roll your own solution. Example follows:

            class Sender : public QObject
            {
                // ...
            signals:
                void signal(int i);
                void finished();
            
                // ...
            };
            
            int main(int argc, char** argv)
            {
                // ...
                auto actions = [&S]() {
                    // ....
                    S->finished();
                };
            
                std::unique_ptr<QThread> Q(new QThread());
                QObject::connect(S.get(), &Sender::finished, R.get(), [&Q] () { Q.get()->quit(); });
                // ...  
                T.join();
                Q->wait();
                // ...
                return 0;
            }
            

            Read and abide by the Qt Code of Conduct

            1 Reply Last reply
            2
            • F Offline
              F Offline
              Feuerteufel
              wrote on last edited by
              #6

              Yeah right, the main loop exists but is not running, that's what I meant but didn't write it correctly. The instantiation of QApplication was needed ( why ever?) to get a event loop running for the QThread, but I don't need to execute the main loop.
              Thanks for your solution, that works not exactly in my case, because I can't change the Sender object (API is fixed). But it can easily be adjust, because the source of the finished signal can be any QObject, e.g. Receiver itself or do I run in another pitfall with that approach?

              //...
              QObject::connect(R.get(), &Receiver::finished, R.get(), [&Q] () { Q->quit(); });
              //...
              T.join();
              emit R->finished();
              Q->wait();
              //...
              

              Am I lost if I can't change Sender and Receiver types? Meaning is the only solution always to have some QObject connected to a lambda calling Q->quit() in context of R?
              Again thanks for your help, enlightend my understanding of how Qt works inside a little bit. As you may notice I'm testing how Qt works in context outside the Qt universe.

              kshegunovK 1 Reply Last reply
              0
              • F Feuerteufel

                Yeah right, the main loop exists but is not running, that's what I meant but didn't write it correctly. The instantiation of QApplication was needed ( why ever?) to get a event loop running for the QThread, but I don't need to execute the main loop.
                Thanks for your solution, that works not exactly in my case, because I can't change the Sender object (API is fixed). But it can easily be adjust, because the source of the finished signal can be any QObject, e.g. Receiver itself or do I run in another pitfall with that approach?

                //...
                QObject::connect(R.get(), &Receiver::finished, R.get(), [&Q] () { Q->quit(); });
                //...
                T.join();
                emit R->finished();
                Q->wait();
                //...
                

                Am I lost if I can't change Sender and Receiver types? Meaning is the only solution always to have some QObject connected to a lambda calling Q->quit() in context of R?
                Again thanks for your help, enlightend my understanding of how Qt works inside a little bit. As you may notice I'm testing how Qt works in context outside the Qt universe.

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

                @Feuerteufel said in Why QThread::wait() never returns after invoked QThread::quit()?:

                The instantiation of QApplication was needed ( why ever?)

                Because Qt is a complex system, and although you don't see it, underneath there are a zillion global variables that need to be initialized. So QApplication should be the first QObject that comes into existence (if you rely on anything QObject related that is).

                But it can easily be adjust, because the source of the finished signal can be any QObject, e.g. Receiver itself or do I run in another pitfall with that approach?

                No, the receiver can emit the signal, provided it knows when the sequence of w/e tasks is finished. Most of the time this isn't true however, so that is the "pitfall". I find your direct call to a signal a bit dubious though. It isn't wrong (syntactically), but the point of signals is they belong to an object, which object itself signals the world about things that happened ...

                Am I lost if I can't change Sender and Receiver types?

                Is deriving from them not an option?

                Meaning is the only solution always to have some QObject connected to a lambda calling Q->quit() in context of R?

                Well, I'd put it in a private slot, but technicalities aside, mostly, yes.

                Read and abide by the Qt Code of Conduct

                1 Reply Last reply
                1
                • F Offline
                  F Offline
                  Feuerteufel
                  wrote on last edited by
                  #8

                  Ok, thanks, I think I have all information I need now.

                  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