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. Safest way to delete workers when TCP server is closing

Safest way to delete workers when TCP server is closing

Scheduled Pinned Locked Moved Unsolved General and Desktop
qthreadmultithreading
14 Posts 4 Posters 3.7k 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.
  • J J.Hilk
    29 Nov 2017, 08:01

    @dream_captain I would suggest doing it with Signal/Slots

    e.g:

    //Assuming:
    QThread *myThread = new QThread();
    Worker *myWorker = new Worker();
    
    //Signal Slots:
    connect(myThread , &QThread::finished,  myThread , &QThread::deleteLater);
    connect(myThread , &QThread::finished,  myWorker , &Worker ::deleteLater);
    connect(qApp, &QApplication::aboutToQuit,   myThread , &QThread::quit);
    
    
    D Offline
    D Offline
    dream_captain
    wrote on 29 Nov 2017, 09:26 last edited by dream_captain
    #4

    @J.Hilk @VRonin
    The code:

    // for each worker call foo(...)
    void foo (Worker *worker, QThread *thread)  {
        connect(thread, &QThread::finished, workerClient, &Worker::deleteLater);
        connect(thread,&QThread::finished,thread,&QThread::deleteLater);
        thread->quit();
    }
    

    results in error: QThread: Destroyed while thread is still running. Seems like i have to handle application close event as @J-Hilk suggested.

    EDIT: Sorry, the error comes from another thread (my tcp server lives in his own thread). This code seems to work fine.

    EDIT2: I've done some testing. It's strange, but destructor of QThread is not called in contrast or worker's destructor when the program is closing.

    V 1 Reply Last reply 29 Nov 2017, 12:50
    0
    • D dream_captain
      29 Nov 2017, 09:26

      @J.Hilk @VRonin
      The code:

      // for each worker call foo(...)
      void foo (Worker *worker, QThread *thread)  {
          connect(thread, &QThread::finished, workerClient, &Worker::deleteLater);
          connect(thread,&QThread::finished,thread,&QThread::deleteLater);
          thread->quit();
      }
      

      results in error: QThread: Destroyed while thread is still running. Seems like i have to handle application close event as @J-Hilk suggested.

      EDIT: Sorry, the error comes from another thread (my tcp server lives in his own thread). This code seems to work fine.

      EDIT2: I've done some testing. It's strange, but destructor of QThread is not called in contrast or worker's destructor when the program is closing.

      V Offline
      V Offline
      VRonin
      wrote on 29 Nov 2017, 12:50 last edited by
      #5
      • the connects should be done when thread and workerClient are created
      • you forgot the "almost" part.

      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
      ~Napoleon Bonaparte

      On a crusade to banish setIndexWidget() from the holy land of Qt

      D 1 Reply Last reply 30 Nov 2017, 05:04
      0
      • V VRonin
        29 Nov 2017, 12:50
        • the connects should be done when thread and workerClient are created
        • you forgot the "almost" part.
        D Offline
        D Offline
        dream_captain
        wrote on 30 Nov 2017, 05:04 last edited by dream_captain
        #6

        @VRonin
        I made a small example illustrating the problem:

        threadex.h

        #ifndef THREADEX_H
        #define THREADEX_H
        
        #include <QThread>
        #include <QDebug>
        
        class ThreadEx : public QThread
        {
            Q_OBJECT
        public:
            explicit ThreadEx(QObject *parent = nullptr) :
                QThread(parent)
            {
                qDebug() << "thread: " << this << "created in: " << QThread::currentThread();
            }
            ~ThreadEx()
            {
                qDebug() << "thread: " << this << "deleted in: " << QThread::currentThread();
            }
        
        };
        #endif // THREADEX_H
        

        main.cpp

        #include <QApplication>
        #include <QWidget>
        
        #include "threadex.h"
        
        int main(int argc, char *argv[])
        {
            QApplication a(argc, argv);
        
            ThreadEx *thread = new ThreadEx;
            QObject::connect(thread, &ThreadEx::finished, thread, &ThreadEx::deleteLater);
            QObject::connect(qApp, &QApplication::aboutToQuit,   thread, &ThreadEx::quit);
            QObject::connect(qApp, &QApplication::aboutToQuit,   []() {
                qDebug() <<  "aboutToQuit()";
            });
            thread->wait();  // don't know why i should block here, but this always returns true
        
            QWidget  widget;
            widget.show();
        
            return a.exec();
        }
        
        

        Output:

        thread:  ThreadEx(0x768ca0) created in:  QThread(0x605fe0)
        aboutToQuit()
        

        ThreadEx::~ThreadEx() is not getting called. How can i be sure that cleanup was successfull and there is no running thread left?

        Just for clarification:
        QObject::deleteLater() documentation says that The object will be deleted when control returns to the event loop. Does that mean that deletion of all QObjects via deleteLater() is controlled by QApplication main event loop?

        J J 2 Replies Last reply 30 Nov 2017, 05:22
        0
        • D dream_captain
          30 Nov 2017, 05:04

          @VRonin
          I made a small example illustrating the problem:

          threadex.h

          #ifndef THREADEX_H
          #define THREADEX_H
          
          #include <QThread>
          #include <QDebug>
          
          class ThreadEx : public QThread
          {
              Q_OBJECT
          public:
              explicit ThreadEx(QObject *parent = nullptr) :
                  QThread(parent)
              {
                  qDebug() << "thread: " << this << "created in: " << QThread::currentThread();
              }
              ~ThreadEx()
              {
                  qDebug() << "thread: " << this << "deleted in: " << QThread::currentThread();
              }
          
          };
          #endif // THREADEX_H
          

          main.cpp

          #include <QApplication>
          #include <QWidget>
          
          #include "threadex.h"
          
          int main(int argc, char *argv[])
          {
              QApplication a(argc, argv);
          
              ThreadEx *thread = new ThreadEx;
              QObject::connect(thread, &ThreadEx::finished, thread, &ThreadEx::deleteLater);
              QObject::connect(qApp, &QApplication::aboutToQuit,   thread, &ThreadEx::quit);
              QObject::connect(qApp, &QApplication::aboutToQuit,   []() {
                  qDebug() <<  "aboutToQuit()";
              });
              thread->wait();  // don't know why i should block here, but this always returns true
          
              QWidget  widget;
              widget.show();
          
              return a.exec();
          }
          
          

          Output:

          thread:  ThreadEx(0x768ca0) created in:  QThread(0x605fe0)
          aboutToQuit()
          

          ThreadEx::~ThreadEx() is not getting called. How can i be sure that cleanup was successfull and there is no running thread left?

          Just for clarification:
          QObject::deleteLater() documentation says that The object will be deleted when control returns to the event loop. Does that mean that deletion of all QObjects via deleteLater() is controlled by QApplication main event loop?

          J Online
          J Online
          jsulm
          Lifetime Qt Champion
          wrote on 30 Nov 2017, 05:22 last edited by
          #7

          @dream_captain said in Safest way to delete workers when TCP server is closing:

          thread->wait();

          why do you call wait?

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

          D 1 Reply Last reply 30 Nov 2017, 05:37
          0
          • J jsulm
            30 Nov 2017, 05:22

            @dream_captain said in Safest way to delete workers when TCP server is closing:

            thread->wait();

            why do you call wait?

            D Offline
            D Offline
            dream_captain
            wrote on 30 Nov 2017, 05:37 last edited by dream_captain
            #8

            @jsulm
            To be sure that the thread has finished. I think that wait() is not necessary when we schedule deletion of QThread.

            1 Reply Last reply
            0
            • D dream_captain
              30 Nov 2017, 05:04

              @VRonin
              I made a small example illustrating the problem:

              threadex.h

              #ifndef THREADEX_H
              #define THREADEX_H
              
              #include <QThread>
              #include <QDebug>
              
              class ThreadEx : public QThread
              {
                  Q_OBJECT
              public:
                  explicit ThreadEx(QObject *parent = nullptr) :
                      QThread(parent)
                  {
                      qDebug() << "thread: " << this << "created in: " << QThread::currentThread();
                  }
                  ~ThreadEx()
                  {
                      qDebug() << "thread: " << this << "deleted in: " << QThread::currentThread();
                  }
              
              };
              #endif // THREADEX_H
              

              main.cpp

              #include <QApplication>
              #include <QWidget>
              
              #include "threadex.h"
              
              int main(int argc, char *argv[])
              {
                  QApplication a(argc, argv);
              
                  ThreadEx *thread = new ThreadEx;
                  QObject::connect(thread, &ThreadEx::finished, thread, &ThreadEx::deleteLater);
                  QObject::connect(qApp, &QApplication::aboutToQuit,   thread, &ThreadEx::quit);
                  QObject::connect(qApp, &QApplication::aboutToQuit,   []() {
                      qDebug() <<  "aboutToQuit()";
                  });
                  thread->wait();  // don't know why i should block here, but this always returns true
              
                  QWidget  widget;
                  widget.show();
              
                  return a.exec();
              }
              
              

              Output:

              thread:  ThreadEx(0x768ca0) created in:  QThread(0x605fe0)
              aboutToQuit()
              

              ThreadEx::~ThreadEx() is not getting called. How can i be sure that cleanup was successfull and there is no running thread left?

              Just for clarification:
              QObject::deleteLater() documentation says that The object will be deleted when control returns to the event loop. Does that mean that deletion of all QObjects via deleteLater() is controlled by QApplication main event loop?

              J Offline
              J Offline
              J.Hilk
              Moderators
              wrote on 30 Nov 2017, 05:56 last edited by
              #9

              @dream_captain
              Good Morning,
              wait will always return true, if the thread is not started, and in your example, the thread is not started. you simply call wait on it.

              To expand your basic example:

              #include <QApplication>
              #include <QWidget>
              
              #include "threadex.h"
              
              int main(int argc, char *argv[])
              {
                  QApplication a(argc, argv);
              
                  ThreadEx *thread = new ThreadEx;
                  QObject::connect(thread, &ThreadEx::finished, thread, &ThreadEx::deleteLater);
                  QObject::connect(qApp, &QApplication::aboutToQuit,   thread, &ThreadEx::quit);
                  QObject::connect(qApp, &QApplication::aboutToQuit,   []() {
                      qDebug() <<  "aboutToQuit()";
                  });
                  thread.start();
              
              ....
              ....
              
                  thread->quit();
                  thread->wait();  
                  
                  QWidget  widget;
                  widget.show();
              
                  return a.exec();
              }
              

              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.

              D 1 Reply Last reply 30 Nov 2017, 06:03
              1
              • J J.Hilk
                30 Nov 2017, 05:56

                @dream_captain
                Good Morning,
                wait will always return true, if the thread is not started, and in your example, the thread is not started. you simply call wait on it.

                To expand your basic example:

                #include <QApplication>
                #include <QWidget>
                
                #include "threadex.h"
                
                int main(int argc, char *argv[])
                {
                    QApplication a(argc, argv);
                
                    ThreadEx *thread = new ThreadEx;
                    QObject::connect(thread, &ThreadEx::finished, thread, &ThreadEx::deleteLater);
                    QObject::connect(qApp, &QApplication::aboutToQuit,   thread, &ThreadEx::quit);
                    QObject::connect(qApp, &QApplication::aboutToQuit,   []() {
                        qDebug() <<  "aboutToQuit()";
                    });
                    thread.start();
                
                ....
                ....
                
                    thread->quit();
                    thread->wait();  
                    
                    QWidget  widget;
                    widget.show();
                
                    return a.exec();
                }
                
                D Offline
                D Offline
                dream_captain
                wrote on 30 Nov 2017, 06:03 last edited by dream_captain
                #10

                @J.Hilk
                Oh, I admit that i simply forget to start the thread. But shouldn't the deletion of thread be handled by QApplication in the snippet below? If i've understood the documentation correctly, there is no need to call quit() and wait() explicitly.

                
                int main(int argc, char *argv[])
                {
                    QApplication a(argc, argv);
                
                    ThreadEx *thread = new ThreadEx;
                
                    QObject::connect(thread, &ThreadEx::finished, thread, &ThreadEx::deleteLater);
                    QObject::connect(qApp, &QApplication::aboutToQuit,   thread, &ThreadEx::quit);
                    QObject::connect(qApp, &QApplication::aboutToQuit,   []() {
                        qDebug() <<  "aboutToQuit()";
                    });
                    thread->start();
                
                    QWidget  widget;
                    widget.show();
                
                    return a.exec();
                }
                

                Still no ThreadEx destructor.

                J J 2 Replies Last reply 30 Nov 2017, 06:11
                0
                • D dream_captain
                  30 Nov 2017, 06:03

                  @J.Hilk
                  Oh, I admit that i simply forget to start the thread. But shouldn't the deletion of thread be handled by QApplication in the snippet below? If i've understood the documentation correctly, there is no need to call quit() and wait() explicitly.

                  
                  int main(int argc, char *argv[])
                  {
                      QApplication a(argc, argv);
                  
                      ThreadEx *thread = new ThreadEx;
                  
                      QObject::connect(thread, &ThreadEx::finished, thread, &ThreadEx::deleteLater);
                      QObject::connect(qApp, &QApplication::aboutToQuit,   thread, &ThreadEx::quit);
                      QObject::connect(qApp, &QApplication::aboutToQuit,   []() {
                          qDebug() <<  "aboutToQuit()";
                      });
                      thread->start();
                  
                      QWidget  widget;
                      widget.show();
                  
                      return a.exec();
                  }
                  

                  Still no ThreadEx destructor.

                  J Offline
                  J Offline
                  J.Hilk
                  Moderators
                  wrote on 30 Nov 2017, 06:11 last edited by
                  #11

                  @dream_captain Well, I'm not entierly sure,

                  I took inspiration from the example in the docs:

                  class Worker : public QObject
                  {
                      Q_OBJECT
                      QThread workerThread;
                  
                  public slots:
                      void doWork(const QString &parameter) {
                          // ...
                          emit resultReady(result);
                      }
                  
                  signals:
                      void resultReady(const QString &result);
                  };
                  
                  class Controller : public QObject
                  {
                      Q_OBJECT
                      QThread workerThread;
                  public:
                      Controller() {
                          Worker *worker = new Worker;
                          worker->moveToThread(&workerThread);
                          connect(&workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
                          connect(this, SIGNAL(operate(QString)), worker, SLOT(doWork(QString)));
                          connect(worker, SIGNAL(resultReady(QString)), this, SLOT(handleResults(QString)));
                          workerThread.start();
                      }
                      ~Controller() {
                          workerThread.quit();
                          workerThread.wait();
                      }
                  public slots:
                      void handleResults(const QString &);
                  signals:
                      void operate(const QString &);
                  };
                  

                  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.

                  1 Reply Last reply
                  0
                  • D Offline
                    D Offline
                    dream_captain
                    wrote on 30 Nov 2017, 06:32 last edited by
                    #12

                    Updated example with Worker object.

                    worker.h

                    #ifndef WORKER_H
                    #define WORKER_H
                    #include <QObject>
                    #include <QDebug>
                    #include <QThread>
                    class Worker : public QObject
                    {
                        Q_OBJECT
                    public:
                        explicit Worker(QObject *parent = nullptr) :
                            QObject(parent)
                        {
                            qDebug() << "worker: " << this << "created in: " << QThread::currentThread();
                        }
                    
                        ~Worker()
                        {
                            qDebug() << "worker: " << this << "deleted in: " << QThread::currentThread();
                        }
                    };
                    #endif // WORKER_H
                    

                    threadex.h

                    #ifndef THREADEX_H
                    #define THREADEX_H
                    #include <QThread>
                    #include <QDebug>
                    class ThreadEx : public QThread
                    {
                        Q_OBJECT
                    public:
                        explicit ThreadEx(QObject *parent = nullptr) :
                            QThread(parent)
                        {
                            qDebug() << "thread: " << this << "created in: " << QThread::currentThread();
                        }
                        ~ThreadEx()
                        {
                            qDebug() << "thread: " << this << "deleted in: " << QThread::currentThread();
                        }
                    };
                    #endif // THREADEX_H
                    

                    main.cpp

                    #include <QApplication>
                    #include <QWidget>
                    
                    #include "threadex.h"
                    #include "worker.h"
                    
                    int main(int argc, char *argv[])
                    {
                        QApplication a(argc, argv);
                    
                        ThreadEx *thread = new ThreadEx;
                    
                        Worker *worker = new Worker;
                    
                        worker->moveToThread(thread);
                    
                        QObject::connect(thread, &ThreadEx::finished, thread, &ThreadEx::deleteLater);
                        QObject::connect(thread, &ThreadEx::finished, worker, &Worker::deleteLater);
                    
                    
                        QObject::connect(qApp, &QApplication::aboutToQuit,   thread, &ThreadEx::quit);
                        QObject::connect(qApp, &QApplication::aboutToQuit,   []() {
                            qDebug() <<  "aboutToQuit()";
                        });
                        thread->start();
                    
                    
                        QWidget  widget;
                        widget.show();
                    
                        return a.exec();
                    }
                    

                    Output:

                    thread:  ThreadEx(0x748d90) created in:  QThread(0x606fe0)
                    worker:  Worker(0x733020) created in:  QThread(0x606fe0)
                    aboutToQuit()
                    worker:  Worker(0x733020) deleted in:  ThreadEx(0x748d90)
                    

                    Looks like QApplication process Worker's deleteLater() fine, but don't want to process ThreadEx's deleteLater().

                    1 Reply Last reply
                    0
                    • D dream_captain
                      30 Nov 2017, 06:03

                      @J.Hilk
                      Oh, I admit that i simply forget to start the thread. But shouldn't the deletion of thread be handled by QApplication in the snippet below? If i've understood the documentation correctly, there is no need to call quit() and wait() explicitly.

                      
                      int main(int argc, char *argv[])
                      {
                          QApplication a(argc, argv);
                      
                          ThreadEx *thread = new ThreadEx;
                      
                          QObject::connect(thread, &ThreadEx::finished, thread, &ThreadEx::deleteLater);
                          QObject::connect(qApp, &QApplication::aboutToQuit,   thread, &ThreadEx::quit);
                          QObject::connect(qApp, &QApplication::aboutToQuit,   []() {
                              qDebug() <<  "aboutToQuit()";
                          });
                          thread->start();
                      
                          QWidget  widget;
                          widget.show();
                      
                          return a.exec();
                      }
                      

                      Still no ThreadEx destructor.

                      J Online
                      J Online
                      jsulm
                      Lifetime Qt Champion
                      wrote on 30 Nov 2017, 07:30 last edited by
                      #13

                      @dream_captain said in Safest way to delete workers when TCP server is closing:

                      But shouldn't the deletion of thread be handled by QApplication in the snippet below?

                      If you do not start the thread finished() signal will not be emitted and deleteLater() slot will not be called.
                      So, if you do not delete the thread explicitly using "delete" it will not be deleted.
                      Who and why should delete it in this case - it does not even have a parent? QApplication does not do memory management.

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

                      D 1 Reply Last reply 30 Nov 2017, 07:40
                      0
                      • J jsulm
                        30 Nov 2017, 07:30

                        @dream_captain said in Safest way to delete workers when TCP server is closing:

                        But shouldn't the deletion of thread be handled by QApplication in the snippet below?

                        If you do not start the thread finished() signal will not be emitted and deleteLater() slot will not be called.
                        So, if you do not delete the thread explicitly using "delete" it will not be deleted.
                        Who and why should delete it in this case - it does not even have a parent? QApplication does not do memory management.

                        D Offline
                        D Offline
                        dream_captain
                        wrote on 30 Nov 2017, 07:40 last edited by dream_captain
                        #14

                        @jsulm
                        Yeah, i understand (just forget to start thread). In that example thread->start() was called though.
                        In the last example deletion of ThreadEx object should be handled by application main loop.

                        1 Reply Last reply
                        0

                        13/14

                        30 Nov 2017, 07:30

                        • Login

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