How to run a task(particular function) independently without blocking my normal flow of code.
-
Hello Guys, I am working on project where I need to Update GUI every 100 ms based on signals I'm getting from controller. In this I need to download a Log file which is present in my controller. I am getting that file using ftp(Qnetworkaccessmanager). I am able to do these task separately. But when I combine it together my UI freezes till the file is downloaded.
I want my UI to update every 100 ms and also want log file to download in background. Please suggest any method.
while searching on Google I found that I can use Qthread to run it independently. so I have tried one example where I run a counter(increment by 1) every 1 sec and I have download button which triggers my thread and downloads the file. But still the counter(UI) freezes till the complete file is downloaded and then continues to increment by 2 which I dont know whys its happening.
I will pasted the whole code down so that u guys can help me figure how to run task independently without waiting for one task.
I am not expert so there might me logic error or something please feel free to suggest them too.Code:
Project Name : test5
All Header filesmythread.h
#ifndef MYTHREAD_H #define MYTHREAD_H #include <QThread> #include <QMutex> class MyThread : public QThread { Q_OBJECT public slots: void stopRunning(); protected: virtual void run(); signals: // void signalValueUpdated(QString); private: bool isRunning; }; #endif // MYTHREAD_H
qftpfiledownload.h
#ifndef QFTPFILEDOWNLOAD_H #define QFTPFILEDOWNLOAD_H //HK 29/3/22 #include<qobject.h> #include<QUrl> #include<QtNetwork/QNetworkAccessManager> #include<QtNetwork/QNetworkRequest> #include<QtNetwork/QNetworkReply> #include<QEventLoop> class QftpFileDownload { public: // QNetworkReply *reply; //HK 29/3/22 QftpFileDownload(QString QftpPathName = "",QString QftpUserName = "", QString QftpPassword = "", QString QftpOutputName =""); // QNetworkAccessManager *nam; // QEventLoop loop; QString getPathName(); QString getUserName(); QString getPassword(); QString getOutputName(); void File_Download(); private: QString QftpPathName; //HK 30/3/22 This requires full path with textfile name eg ."ftp://169.254.10.102/test.txt" QString QftpUserName; QString QftpPassword; QString QftpOutputName; }; #endif // QFTPFILEDOWNLOAD_H
test5.h
#ifndef TEST5_H #define TEST5_H #include <QMainWindow> #include<QString> #include<QTimer> #include"mythread.h" namespace Ui { class test5; } class test5 : public QMainWindow { Q_OBJECT public: explicit test5(QWidget *parent = 0); ~test5(); unsigned int counter = 0; void display_time(); private slots: void on_pushButton_clicked(); void updateTimer(); signals: void download_button_clicked(); private: Ui::test5 *ui; QTimer *Timer; MyThread thread; }; #endif // TEST5_H
All source files
main.cpp
#include "test5.h" #include <QApplication> #include"ui_test5.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); test5 w; w.show(); return a.exec(); }
mythread.cpp
#include "mythread.h" #include <QString> #include"qftpfiledownload.h" void MyThread::run() { qDebug("Thread id inside run %d",*((int*)QThread::currentThreadId())); isRunning = 1; QftpFileDownload object("ftp://169.254.10.102/test_100mb.txt","Administrator","Nopass123","Mytesting100.txt"); object.File_Download(); } void MyThread::stopRunning() { isRunning = 0; }
qftpfiledownload.cpp
#include "qftpfiledownload.h" //HK 29/3/22 #include<QUrl> #include<QtNetwork/QNetworkAccessManager> #include<QtNetwork/QNetworkRequest> #include<QtNetwork/QNetworkReply> #include<QEventLoop> #include<QFile> #include"test5.h" QftpFileDownload::QftpFileDownload(QString QftpPathName, QString QftpUserName, QString QftpPassword, QString QftpOutputName) { this->QftpPathName = QftpPathName; this->QftpUserName = QftpUserName; this->QftpPassword = QftpPassword; this->QftpOutputName = QftpOutputName; } QString QftpFileDownload::getPathName() { return QftpPathName; } QString QftpFileDownload::getUserName() { return QftpUserName; } QString QftpFileDownload::getPassword() { return QftpPassword; } QString QftpFileDownload::getOutputName() { return QftpOutputName; } void QftpFileDownload::File_Download() { QEventLoop loop; QNetworkAccessManager *nam = new QNetworkAccessManager(); QObject::connect(nam, &QNetworkAccessManager::finished, &loop, &QEventLoop::quit); qDebug()<<"Inside Function"; test5 time; time.display_time(); // QUrl url2("ftp://169.254.10.102/test.txt"); QUrl url2(QftpPathName); // url2.setPassword("Nopass123"); // url2.setUserName("Administrator"); url2.setPassword(QftpPassword); url2.setUserName(QftpUserName); QNetworkRequest req(url2); QNetworkReply *reply = nam->get(req); loop.exec(); QFile file(QftpOutputName); file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); out<< reply->readAll(); file.close(); reply->deleteLater(); qDebug()<<"Last line"; time.display_time(); }
test5.cpp
#include "test5.h" #include "ui_test5.h" #include"qftpfiledownload.h" #include"time.h" //#include"mythread.h" test5::test5(QWidget *parent) : QMainWindow(parent), ui(new Ui::test5) { ui->setupUi(this); Timer = new QTimer(); connect(Timer,SIGNAL(timeout()),this,SLOT(updateTimer())); Timer->start(1000); qDebug("Thread id %d",*((int*)QThread::currentThreadId())); //When the start button is pressed, invoke the start() method in the counter thread QObject::connect(this,SIGNAL(download_button_clicked()),&thread,SLOT(start()), Qt::QueuedConnection); //When the stop button is pressed, invoke the stop() method in the counter thread //QObject::connect(stopButton,SIGNAL(clicked()),&thread,SLOT(stopRunning()), Qt::QueuedConnection); //When the counter thread emits a signal saying its value has been updated, reflect that change in the lineEdit field. //QObject::connect(&thread,SIGNAL(signalValueUpdated(const QString&)),lineEdit,SLOT(setText(const QString&)), Qt::QueuedConnection); // if(counter % 1000 == 0) // { // ui->Counter->setText(QString(counter)); // counter =0; // } } test5::~test5() { delete ui; } void test5::on_pushButton_clicked() { // QftpFileDownload object("ftp://169.254.10.102/test_100mb.txt","Administrator","Nopass123","Mytesting100.txt"); // object.File_Download(); emit download_button_clicked(); } void test5::updateTimer() { static unsigned int Counter=0; ui->Counter->setText(QString::number(Counter)); Counter++; } void test5::display_time() { time_t rawtime; struct tm * timeinfo; time(&rawtime); timeinfo = localtime( &rawtime); qDebug("%02d:%02d:%02d\n",timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); // char output[8]; // sprintf(output,"%02d:%02d:%02d",timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); // printf("%s\t",output); // printf("%d\n",sizeof(output)); }
test5.ui
I will paste the pro file too so that u guys can copy this and workout on this project
#------------------------------------------------- # # Project created by QtCreator 2022-03-31T10:12:10 # #------------------------------------------------- QT += core gui network greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = test5 TEMPLATE = app # The following define makes your compiler emit warnings if you use # any feature of Qt which has been marked as deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ test5.cpp \ qftpfiledownload.cpp \ mythread.cpp HEADERS += \ test5.h \ qftpfiledownload.h \ mythread.h FORMS += \ test5.ui
Thanks in advance
-
In first place, why you need to have threads at all?
QNetworkAccessManager
works asynchronous using signals and slots. -
Your whole code / structure is quite confusing. AFAICS there's no need to create a
QThread
derived class.
If you want to increment your counter once a download is finished, just connect to thefinished
signal.You could check out this example:
and @VRonin 's reply here:
-
Hi,
You have:
loop.exec();
In your code which will block the execution until the loop exits.
As you were already told, don't do that.
-
@HimanshuKaushik said in How to run a task(particular function) independently without blocking my normal flow of code.:
I am getting empty file when removing
Because you have to do a bit more than just removing loop.exec()!
You need to write the file when you get all the data.
Please take a look at available examples, there is even one for downloading data: https://doc.qt.io/qt-5/qtnetwork-downloadmanager-example.html