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 cleaning up when application terminates
Forum Update on Monday, May 27th 2025

QThread cleaning up when application terminates

Scheduled Pinned Locked Moved Solved General and Desktop
5 Posts 2 Posters 167 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.
  • SPlattenS Offline
    SPlattenS Offline
    SPlatten
    wrote on last edited by
    #1

    I have a class that receives files via TCP, the prototype:

    class TcpBinaryReceiver : public QTcpServer
    {
        Q_OBJECT
     
    public:
        explicit TcpBinaryReceiver(QObject* pParent = nullptr);
        void startServer();
     
    protected:
        void incomingConnection(qintptr socketDescriptor);
     
    signals:
        void onTcpReceived(qintptr socketDescriptor, quint32 uint32PacketNo,
                           int intReceived);
    };
     
    class ConnectionToTrainer : public QThread
    {
        Q_OBJECT
     
    private:
        QFile* mpobjRxFile;
        QTcpSocket* mpsckCli;
        qintptr msckDescriptor;
        QTimer mtmrRxEnd;
        quint32 muint32PacketNo;
        quint64 muint64Received;
     
    public:
        static const quint16 mscuint16RxEndTimeout;
     
        explicit ConnectionToTrainer(qintptr ID, QObject* pParent = nullptr);
        void run();
     
    signals:
        void error(QTcpSocket::SocketError sckError);
        void kick();
        void tcpReceived(qintptr msckDescriptor, quint32 uint32PacketNo,
                         int intReceived);
     
    public slots:
        void disconnected();
        void onKick();
        void readyRead();
    };
    

    The implementation:

    /**
     * @brief TcpBinaryReceiver::TcpBinaryReceiver
     * @param pParent Pointer to parent
     */
    TcpBinaryReceiver::TcpBinaryReceiver(QObject* pParent) : QTcpServer(pParent)
    {
        
    }
    /**
     * @brief TcpBinaryReceiver::startServer
     */
    void TcpBinaryReceiver::startServer()
    {
        quint16 uint16Port(SckServer::uint16PortTCP());
        if ( !this->listen(QHostAddress::Any, uint16Port) )
        {
            qDebug() << "Could not start TCP server!";
        }
        else
        {
            qDebug() << "Listening to port " << uint16Port << "...";
        }
    }
    /**
     * @brief TcpBinaryReceiver::incomingConnection
     * @param socketDescriptor  details of new connection
     */
    void TcpBinaryReceiver::incomingConnection(qintptr socketDescriptor)
    {
        qDebug() << socketDescriptor << " Connecting...";
        ConnectionToTrainer* pThread(new ConnectionToTrainer(socketDescriptor, this));
        QObject::connect(pThread, &ConnectionToTrainer::finished,
            [this]()
            {
                deleteLater();
            }
        );
                         //pThread, &ConnectionToTrainer::deleteLater);
        QObject::connect(pThread, &ConnectionToTrainer::tcpReceived,
                         this, &TcpBinaryReceiver::onTcpReceived);
        pThread->start();
    }
    //Static initialisation
    const quint16 ConnectionToTrainer::mscuint16RxEndTimeout = 1000.0;
    /**
     * @brief ConnectionToTrainer::ConnectionToTrainer
     * @param ID Socket descriptor
     * @param pParent   Pointer to parent
     */
    ConnectionToTrainer::ConnectionToTrainer(qintptr ID, QObject* pParent)
        : QThread(pParent),
          mpobjRxFile(nullptr),
          mpsckCli(nullptr),
          msckDescriptor(ID),
          muint32PacketNo(0),
          muint64Received(0)
    {
        QObject::connect(this, &ConnectionToTrainer::kick,
                         this, &ConnectionToTrainer::onKick);
        QObject::connect(&mtmrRxEnd, &QTimer::timeout,
            [this]()
            {
                if ( muint64Received > 0 )
                {
        //File received
                    DatasetTransfer* pobjTransfer(DatasetTransfer::pCurrentTransfer());
                    if ( pobjTransfer != nullptr )
                    {
                        QFile& rFile(pobjTransfer->rFile());
                        emit pobjTransfer->transferComplete(rFile.fileName());
                    }
                }
                mtmrRxEnd.stop();
            }
        );
    }
    /**
     * @brief ConnectionToTrainer::disconnected
     */
    void ConnectionToTrainer::disconnected()
    {
        mpsckCli->deleteLater();
    }
    /**
     * @brief ConnectionToTrainer::onKick
     */
    void ConnectionToTrainer::onKick()
    {
        mtmrRxEnd.start(ConnectionToTrainer::mscuint16RxEndTimeout);
    }
    /**
     * @brief ConnectionToTrainer::run
     */
    void ConnectionToTrainer::run()
    {
        mpsckCli = new QTcpSocket(this);
        muint32PacketNo = 0;
        muint64Received = 0;
        //Set the ID
        if ( !mpsckCli->setSocketDescriptor(msckDescriptor) )
        {
            emit error(mpsckCli->error());
            return;
        }
        //Connect signals
        QObject::connect(mpsckCli, &QTcpSocket::connected,
            [this]()
            {
               qdbg() << "mpsckCli::connected!";
            }
        );
        QObject::connect(mpsckCli, &QTcpSocket::disconnected,
                         this, &ConnectionToTrainer::disconnected);
        QObject::connect(mpsckCli, &QTcpSocket::readyRead,
                         this, &ConnectionToTrainer::readyRead,
                         Qt::DirectConnection);
        DatasetTransfer* pobjTransfer(DatasetTransfer::pCurrentTransfer());
        if ( pobjTransfer == nullptr )
        {
            return;
        }
        mpobjRxFile = &pobjTransfer->rFile();
        //Thread loop
        exec();
    }
    /**
     * @brief ConnectionToTrainer::readyRead
     */
    void ConnectionToTrainer::readyRead()
    {
        Q_ASSERT_X(mpobjRxFile!=nullptr, "ConnectionToTrainer::readyRead",
                   ConnectionToTrainer::tr("Receive file has not been connected!")
                   .toLatin1().data());
        QByteArray baData(mpsckCli->readAll());
        int intReceived(baData.size());
        if ( intReceived > 0 && mpobjRxFile->isOpen() == true )
        {
            qint64 int64Written(mpobjRxFile->write(baData.data(), intReceived));
            if ( intReceived != int64Written )
            {
                return;
            }
    qdbg() << "ConnectionToTrainer::readyRead, intReceived: " << intReceived;
            emit tcpReceived(msckDescriptor, muint32PacketNo, intReceived);
            muint64Received += intReceived;
            muint32PacketNo++;
        }
        emit kick();
    }
    

    This works ok, the problem is when the application is closed I get a Qt critical error handler dialog, Abort, Retry, Ignore.

    How can I terminate any threads when the application is closing down?

    Kind Regards,
    Sy

    jsulmJ 1 Reply Last reply
    0
    • SPlattenS SPlatten

      I have a class that receives files via TCP, the prototype:

      class TcpBinaryReceiver : public QTcpServer
      {
          Q_OBJECT
       
      public:
          explicit TcpBinaryReceiver(QObject* pParent = nullptr);
          void startServer();
       
      protected:
          void incomingConnection(qintptr socketDescriptor);
       
      signals:
          void onTcpReceived(qintptr socketDescriptor, quint32 uint32PacketNo,
                             int intReceived);
      };
       
      class ConnectionToTrainer : public QThread
      {
          Q_OBJECT
       
      private:
          QFile* mpobjRxFile;
          QTcpSocket* mpsckCli;
          qintptr msckDescriptor;
          QTimer mtmrRxEnd;
          quint32 muint32PacketNo;
          quint64 muint64Received;
       
      public:
          static const quint16 mscuint16RxEndTimeout;
       
          explicit ConnectionToTrainer(qintptr ID, QObject* pParent = nullptr);
          void run();
       
      signals:
          void error(QTcpSocket::SocketError sckError);
          void kick();
          void tcpReceived(qintptr msckDescriptor, quint32 uint32PacketNo,
                           int intReceived);
       
      public slots:
          void disconnected();
          void onKick();
          void readyRead();
      };
      

      The implementation:

      /**
       * @brief TcpBinaryReceiver::TcpBinaryReceiver
       * @param pParent Pointer to parent
       */
      TcpBinaryReceiver::TcpBinaryReceiver(QObject* pParent) : QTcpServer(pParent)
      {
          
      }
      /**
       * @brief TcpBinaryReceiver::startServer
       */
      void TcpBinaryReceiver::startServer()
      {
          quint16 uint16Port(SckServer::uint16PortTCP());
          if ( !this->listen(QHostAddress::Any, uint16Port) )
          {
              qDebug() << "Could not start TCP server!";
          }
          else
          {
              qDebug() << "Listening to port " << uint16Port << "...";
          }
      }
      /**
       * @brief TcpBinaryReceiver::incomingConnection
       * @param socketDescriptor  details of new connection
       */
      void TcpBinaryReceiver::incomingConnection(qintptr socketDescriptor)
      {
          qDebug() << socketDescriptor << " Connecting...";
          ConnectionToTrainer* pThread(new ConnectionToTrainer(socketDescriptor, this));
          QObject::connect(pThread, &ConnectionToTrainer::finished,
              [this]()
              {
                  deleteLater();
              }
          );
                           //pThread, &ConnectionToTrainer::deleteLater);
          QObject::connect(pThread, &ConnectionToTrainer::tcpReceived,
                           this, &TcpBinaryReceiver::onTcpReceived);
          pThread->start();
      }
      //Static initialisation
      const quint16 ConnectionToTrainer::mscuint16RxEndTimeout = 1000.0;
      /**
       * @brief ConnectionToTrainer::ConnectionToTrainer
       * @param ID Socket descriptor
       * @param pParent   Pointer to parent
       */
      ConnectionToTrainer::ConnectionToTrainer(qintptr ID, QObject* pParent)
          : QThread(pParent),
            mpobjRxFile(nullptr),
            mpsckCli(nullptr),
            msckDescriptor(ID),
            muint32PacketNo(0),
            muint64Received(0)
      {
          QObject::connect(this, &ConnectionToTrainer::kick,
                           this, &ConnectionToTrainer::onKick);
          QObject::connect(&mtmrRxEnd, &QTimer::timeout,
              [this]()
              {
                  if ( muint64Received > 0 )
                  {
          //File received
                      DatasetTransfer* pobjTransfer(DatasetTransfer::pCurrentTransfer());
                      if ( pobjTransfer != nullptr )
                      {
                          QFile& rFile(pobjTransfer->rFile());
                          emit pobjTransfer->transferComplete(rFile.fileName());
                      }
                  }
                  mtmrRxEnd.stop();
              }
          );
      }
      /**
       * @brief ConnectionToTrainer::disconnected
       */
      void ConnectionToTrainer::disconnected()
      {
          mpsckCli->deleteLater();
      }
      /**
       * @brief ConnectionToTrainer::onKick
       */
      void ConnectionToTrainer::onKick()
      {
          mtmrRxEnd.start(ConnectionToTrainer::mscuint16RxEndTimeout);
      }
      /**
       * @brief ConnectionToTrainer::run
       */
      void ConnectionToTrainer::run()
      {
          mpsckCli = new QTcpSocket(this);
          muint32PacketNo = 0;
          muint64Received = 0;
          //Set the ID
          if ( !mpsckCli->setSocketDescriptor(msckDescriptor) )
          {
              emit error(mpsckCli->error());
              return;
          }
          //Connect signals
          QObject::connect(mpsckCli, &QTcpSocket::connected,
              [this]()
              {
                 qdbg() << "mpsckCli::connected!";
              }
          );
          QObject::connect(mpsckCli, &QTcpSocket::disconnected,
                           this, &ConnectionToTrainer::disconnected);
          QObject::connect(mpsckCli, &QTcpSocket::readyRead,
                           this, &ConnectionToTrainer::readyRead,
                           Qt::DirectConnection);
          DatasetTransfer* pobjTransfer(DatasetTransfer::pCurrentTransfer());
          if ( pobjTransfer == nullptr )
          {
              return;
          }
          mpobjRxFile = &pobjTransfer->rFile();
          //Thread loop
          exec();
      }
      /**
       * @brief ConnectionToTrainer::readyRead
       */
      void ConnectionToTrainer::readyRead()
      {
          Q_ASSERT_X(mpobjRxFile!=nullptr, "ConnectionToTrainer::readyRead",
                     ConnectionToTrainer::tr("Receive file has not been connected!")
                     .toLatin1().data());
          QByteArray baData(mpsckCli->readAll());
          int intReceived(baData.size());
          if ( intReceived > 0 && mpobjRxFile->isOpen() == true )
          {
              qint64 int64Written(mpobjRxFile->write(baData.data(), intReceived));
              if ( intReceived != int64Written )
              {
                  return;
              }
      qdbg() << "ConnectionToTrainer::readyRead, intReceived: " << intReceived;
              emit tcpReceived(msckDescriptor, muint32PacketNo, intReceived);
              muint64Received += intReceived;
              muint32PacketNo++;
          }
          emit kick();
      }
      

      This works ok, the problem is when the application is closed I get a Qt critical error handler dialog, Abort, Retry, Ignore.

      How can I terminate any threads when the application is closing down?

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

      @SPlatten https://doc.qt.io/qt-5/qcoreapplication.html#aboutToQuit - connect a slot to this signal and ask all your active threads to finish.
      https://doc.qt.io/qt-5/qthread.html#quit
      https://doc.qt.io/qt-5/qthread.html#wait-1

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

      SPlattenS 1 Reply Last reply
      4
      • jsulmJ jsulm

        @SPlatten https://doc.qt.io/qt-5/qcoreapplication.html#aboutToQuit - connect a slot to this signal and ask all your active threads to finish.
        https://doc.qt.io/qt-5/qthread.html#quit
        https://doc.qt.io/qt-5/qthread.html#wait-1

        SPlattenS Offline
        SPlattenS Offline
        SPlatten
        wrote on last edited by
        #3

        @jsulm , Thank you, how do you get a pointer to QCoreApplication? In main():

        QApplication a(argc, argv);
        

        Is there a way to access QCoreApplication with an API call?

        Kind Regards,
        Sy

        jsulmJ 1 Reply Last reply
        0
        • SPlattenS SPlatten

          @jsulm , Thank you, how do you get a pointer to QCoreApplication? In main():

          QApplication a(argc, argv);
          

          Is there a way to access QCoreApplication with an API call?

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

          @SPlatten https://doc.qt.io/qt-5/qapplication.html#qApp

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

          SPlattenS 1 Reply Last reply
          3
          • jsulmJ jsulm

            @SPlatten https://doc.qt.io/qt-5/qapplication.html#qApp

            SPlattenS Offline
            SPlattenS Offline
            SPlatten
            wrote on last edited by
            #5

            @jsulm Thank you.

            Kind Regards,
            Sy

            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