GUI Freeze when terminating the QThread.
-
Dear all,
I am using a thread that read data from a sql lite database in a while loop. I do some actions in my main windows based in the data I read in my thread class. I have two button in my GUI. One button start the thread and another button terminate the thread. Now I am facing two issues.- After I terminate the thread, I see my GUI freeze for few seconds.
- After the GUI recover, when I try to update the data in the table, I get errorr: QSqlError("5", "Unable to fetch row", "database is locked"). I was believing that after I terminate the thread, my db connection is also closed but seems not.
I need the help of the experts what I can do to correct my code.
my code to terminate the thread on button click:
void MainWindow::on_pushButton_ExitJob_clicked() { scaraPositions->exit(); scaraPositions->quit(); scaraPositions->terminate(); }
my thread class code:
#include "scaraPositions.h" #include<QDebug> #include<QSqlError> ScaraPositions::ScaraPositions() { qRegisterMetaType<int64_t>("int64_t"); mySqlLiteDB =QSqlDatabase::addDatabase("QSQLITE","3"); mySqlLiteDB.setDatabaseName(SQLLiteDBPath); if(mySqlLiteDB.open()) { qDebug()<<"connected in scara positions"; mySqlLiteDB.close(); } else { qDebug()<<"NOT connected in scara positions"; } } void ScaraPositions::run() { int joint1; int joint2; QString position; connection: if(mySqlLiteDB.open()) { while(true) { QSqlQuery query("",mySqlLiteDB); QSqlQuery query1("",mySqlLiteDB); query.exec(NextScaraPosition); while (query.next()) { counter=0; position = query.value(0).toString(); joint1 = query.value(1).toInt(); joint2 = query.value(2).toInt(); //qDebug()<<"INFO: PROCESSING "<<"position sequence:"<<position; query1.exec(CheckNotMovingJointStatus); while (query1.next()) { counter++; } query1.finish(); if(counter==2) { emit this->sendJoint1Position(joint1,position); emit this->sendJoint2Position(joint2); counter=0; } } query.finish(); } //mySqlLiteDB.close(); } else { sleep(5); goto connection; } }
-
You must not use a QSqlDatabase connection created in one thread in another.
Also you must not store the QSqlDatabase connection in a local member variable. See https://doc.qt.io/qt-5/qsqldatabase.html#detailsQSqlQuery query("",mySqlLiteDB); QSqlQuery query1("",mySqlLiteDB);
How is this supposed to work?
-
Hi @Christian-Ehrlicher thanks for your reply. As per your suggestion, I created a new class dbmanager and added the constructor.
I am using two threads jointstatus.cpp and scarapositions.cpp. Both the classes are reading data from sqllite db. I have created the object of dbmanager class in scarapositions.cpp likevoid ScaraPositions::run() { DbManager dbManager("ScaraPositions");
and its working as I am calling only the run function of this thread.
But in the case of jointstatus.cpp, I have several functions which are calling database. I tried putting this line in header file jointstatus.hDbManager dbManager;
bit it gives error, DBManager does not name a type.
Then I tried creating the object of DbManager inside the cpp file, but I getQSqlDatabasePrivate::addDatabase: duplicate connection name 'JointStatus1', old connection removed. QSqlDatabasePrivate::addDatabase: duplicate connection name 'JointStatus2', old connection removed.
and here is the code of jointstatus.cpp
void JointStatus::UpdateJoint1Status(QString status) { DbManager dbManager("JointStatus1"); if(this->Joint1Status!=status){ this->Joint1Status=status; if(status=="1237"){ if (dbManager.isOpen()) { dbManager.Joint1StatusMovingUpdate(); } } UpdatePositionData(this->positionIdentifier,"Processing"); } else if(status=="1637") { if (dbManager.isOpen()) { dbManager.Joint1StatusNotMovingUpdate(); } } //dbManager.~DbManager(); } void JointStatus::UpdateJoint2Status(QString status) { DbManager dbManager("JointStatus2"); if(this->Joint2Status!=status) { this->Joint2Status=status; if(status=="1237"){ if (dbManager.isOpen()) { dbManager.Joint2StatusMovingUpdate(); } } else if(status=="1637") { if (dbManager.isOpen()) { dbManager.Joint2StatusNotMovingUpdate(); } UpdatePositionData(this->positionIdentifier,"Completed"); } } //dbManager.~DbManager(); }
I believe I am not following the right way to call the DbManager class. I need to call this DbManager class from my mainwindow and 2 threads so that I can fetch data and take actions.
Need guidance please. -
@qtwithanzo
are you aware, you're damning your soul to eternal damnation here ?else { sleep(5); goto connection; }
😱
the guy freeze is probably coming from this.
scaraPositions->exit(); scaraPositions->quit(); scaraPositions->terminate();
exit and quit have no meaning/function since you do not use the exec() function/eventloop of the QThread object, you can drop it.
and terminate relies solely on the operating system to terminate the thread, that my happen immediately or whenever it feels like it.
also seeing this warning in the documentation:
https://doc.qt.io/qt-5/qthread.html#terminateWarning: This function is dangerous and its use is discouraged. The thread can be terminated at any point in its code path. Threads can be terminated while modifying data. There is no chance for the thread to clean up after itself, unlock any held mutexes, etc. In short, use this function only if absolutely necessary.
there is no guarantee that your database is closed correctly, in fact it will be a small miracle if it happens.
-
Thanks for your valuable feedback. My screen is not freezing now. :)