Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Problems use QFtp in QThread



  • Hi Guys, I use QFtp in my project, now I faced a strange problem. The codes as follows:

    class FtpOutput: public QObject{
    private:
    QFtp* mQFtpPtr = nullptr;
    } 
    
    MyApp::MyApp(QObject *parent) : QObject(parent){
        mFtpThread = new QThread;
        mFtpOutput = new FtpOutput;
        mFtpOutput->setUrlStr("127.0.0.1");
        mFtpOutput->moveToThread(mFtpThread);
        connect(mFtpThread, &QThread::started, mFtpOutput, &FtpOutput::run);
        connect(mFtpThread, &QThread::destroyed, mFtpOutput, &FtpOutput::deleteLater);
        mFtpThread->start();
    }
    
    void FtpOutput::run()
    {
        static FileDescriptorPtr filePtr;
    
        if(mQFtpPtr == nullptr) {
            mQFtpPtr = new QFtp(this);
            //![1]
            this->connect(this, &FtpOutput::destroyed, mQFtpPtr, &QFtp::deleteLater);
    
            this->connect(mQFtpPtr, SIGNAL(commandFinished(int,bool)),
                          this, SLOT(onFtpCommandFinished(int,bool)));
            this->connect(mQFtpPtr, SIGNAL(dataTransferProgress(qint64,qint64)),
                          this, SLOT(onDataTransferProgress(qint64,qint64)));
            this->connect(mQFtpPtr, SIGNAL(stateChanged(int)),
                          this, SLOT(onStatusChange(int)));
            this->connect(mQFtpPtr, SIGNAL(listInfo(QUrlInfo)),
                          this, SLOT(onListInfo(QUrlInfo)));
            //![1]
        }
    
        QThread::msleep(100);
    
        int state = mQFtpPtr->state();
        //Step 1 check connection
        if(state == QFtp::Unconnected && mStep == 0) {
            doConnect();
            mStep = 1;
    }
    }
    

    The problem is when exec the doConnect(), nothing happens, but when I use QFtp directly from GUI( not use QThread), everything goes well.
    I tracked that:

    int QFtpPrivate::addCommand(QFtpCommand *cmd)
    {
        pending.append(cmd);
    
        if (pending.count() == 1) {
            // don't emit the commandStarted() signal before the ID is returned
            QTimer::singleShot(0, q_func(), SLOT(_q_startNextCommand()));
        } else {
            qDebug()<<"pending count:"<<pending.count();
        }
        return cmd->id;
    }
    

    When the code QTimer::singleShot exec,
    the _q_startNextCommand slot function not exec. Please help me.



  • @Bruce-Zhang Your code cannot work QThread::msleep(100); is an "active wait", so the QEventLoop of the thread is locked and all signals are not executed!

    I would also recommend you to use new connect syntax to allow signals/slots validity check at compilation.

    void FtpOutput::run()
    {
        if(mQFtpPtr == nullptr) {
            mQFtpPtr = new QFtp(this);
    		// => not needed, because this is parent
            //connect(this, &FtpOutput::destroyed, mQFtpPtr, &QFtp::deleteLater);
            connect(mQFtpPtr, &QFtp::commandFinished, this, &FtpOutput::onFtpCommandFinished);
            connect(mQFtpPtr, &QFtp::dataTransferProgress, this, &FtpOutput::onDataTransferProgress);
            connect(mQFtpPtr, &QFtp::stateChanged, this, &FtpOutput::onStatusChange);
            connect(mQFtpPtr, &QFtp::listInfo, this, &FtpOutput::onListInfo);
    
    		//Step 1 start connection
            doConnect();
            mStep = 1;
        }
    }
    


  • @Bruce-Zhang Your code cannot work QThread::msleep(100); is an "active wait", so the QEventLoop of the thread is locked and all signals are not executed!

    I would also recommend you to use new connect syntax to allow signals/slots validity check at compilation.

    void FtpOutput::run()
    {
        if(mQFtpPtr == nullptr) {
            mQFtpPtr = new QFtp(this);
    		// => not needed, because this is parent
            //connect(this, &FtpOutput::destroyed, mQFtpPtr, &QFtp::deleteLater);
            connect(mQFtpPtr, &QFtp::commandFinished, this, &FtpOutput::onFtpCommandFinished);
            connect(mQFtpPtr, &QFtp::dataTransferProgress, this, &FtpOutput::onDataTransferProgress);
            connect(mQFtpPtr, &QFtp::stateChanged, this, &FtpOutput::onStatusChange);
            connect(mQFtpPtr, &QFtp::listInfo, this, &FtpOutput::onListInfo);
    
    		//Step 1 start connection
            doConnect();
            mStep = 1;
        }
    }
    


  • @KroMignon said in Problems use QFtp in QThread:

    connect(mQFtpPtr, &QFtp::commandFinished, this, &FtpOutput::onFtpCommandFinished);
    connect(mQFtpPtr, &QFtp::dataTransferProgress, this, &FtpOutput::onDataTransferProgress);
    connect(mQFtpPtr, &QFtp::stateChanged, this, &FtpOutput::onStatusChange);
    connect(mQFtpPtr, &QFtp::listInfo, this, &FtpOutput::onListInfo);

    Thanks a lot, really works.


Log in to reply