PDA

View Full Version : Two connections from two threads to one database



Vesa95
11th July 2019, 13:23
For a few days I'm still struggling to make this code work. I have one database (SQLITE), to which I connect at the beginning of the program.

QString path: "xxxxx";
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(path);
if(db.open())
qDebug()<<"database"<<path<<"opened";
else {
qDebug()<<"unable to open database"<<path;
}

/* FOR THE SAKE OF EXAMPLE
QSqlQuery query;
bool result=query.exec("CREATE TABLE IF NOT EXISTS compdefs "
"(id INTEGER PRIMARY KEY AUTOINCREMENT, "
"name VARCHAR(20), "
"minarea INTEGER, "
"aspectratio DOUBLE,"
"orientationmode INTEGER,"
"upsample INTEGER,"
"horizontalflip BOOLEAN NOT NULL CHECK (horizontalflip IN (0,1)),"
"verticalflip BOOLEAN NOT NULL CHECK (verticalflip IN (0,1)),"
"c DOUBLE,"
"eps DOUBLE,"
"numthreads INTEGER,"
"trainedfhog BOOLEAN NOT NULL DEFAULT 0,");

*/

Everything work fine, I can add, or remove from database as I want. But, in one moment, I need to push a button, this button create a QtConcurentRun, which call another thread to do my training HOG classifier function, and my main thread keep my GUI unfreeze!

But when my train HOG classifier function is complete, i need to save those data in my sqlite database, which is in my main thread and when I try to save those data, I get this error:

QSqlDatabasePrivate::database: requested database does not belong to the calling thread.
Is any method to update my database from the second thread? Maybe create a second connection? How I do this? If I create a second connection I need to remove fisrt connection? Please, I need some help.

This is my part of code, when I push the button.


void CompDefDialog::on_fhogTrainBtn_clicked(){
//other stuff
trainHOGFuture = QtConcurrent::run(compDef, &CompDef::trainFHOG);
}


and this is my trahinFHOG function who start in the second thread:



void CompDef::trainFHOG(void)
{
QElapsedTimer timer;
timer.start();
//other stuff
// from this line, I start to save my new data in my database
if(id<=0)
{
qDebug()<<"save component definition first";
return;
}

trainedFHOG=true;
oldFHOG=false;

QSqlQuery query;
std::ostringstream buf;
dlib::serialize(fhogDetector, buf);

QString sql="UPDATE compdefs SET fhogclassifier= :classifier, "
"trainedfhog= :trainedfhog, "
"oldfhog= :oldfhog "
"WHERE id=:id";

query.prepare(sql);
query.bindValue(":classifier", QByteArray(buf.str().c_str(),buf.str().length()));
query.bindValue(":id", id);
query.bindValue(":trainedfhog", trainedFHOG);
query.bindValue(":oldfhog", oldFHOG);

if(!query.exec())
{
qDebug()<<"error while saving fhog classifier:"<<query.lastError()<<query.lastQuery();
qDebug() << QSqlDatabase::drivers();
}
}

^NyAw^
11th July 2019, 13:46
Hi,

When the thread execution finish the training process you can emit a signal to the mainThread and let the mainThread get the object data to store it into the database. You have to let the mainThread access to the CompDef members data via method.

anda_skoa
11th July 2019, 14:53
Couple of options

1) Store the data in a member variable of the class, of course with proper locking and handle the database query in the main thread once the function has finished

2) Return the data from the trainFHOG() function, retrieve from the future after completion and do the database interaction in the main thread

3) As ^NyAw^ suggested emitting the data from the trainFHOG() using a signal, then do the database interaction in the main thread

4) Create a new database connection inside the trainFHOG() function using QSqlDataBase::addDatabase() with different name than the one used on the main thread.
Also obviously calling removeDatabase() before returning.

Cheers,
_