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 Updated to NodeBB v4.3 + New Features

QThread cleaning up when application terminates

Scheduled Pinned Locked Moved Solved General and Desktop
5 Posts 2 Posters 169 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.
  • 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