I'm writing a QT program with a lot of database queries.
The QSqlDatabase is not thread safe as the documents states.
So I wrote a simple thread_local QSqlDatabase to maintain a database connection per thread.
class Database
{
public:
static Database& Database::get()
{
thread_local static Database database;
return database;
}
Database::~Database()
{
if (close()) {
QSqlDatabase::removeDatabase(this->dbname);
}
}
private:
Database::Database() {
this->dbname ="my_db_" + QString::number((quint64)QThread::currentThread(), 16);
if(QSqlDatabase::contains(this->dbname))
this->db = QSqlDatabase::database(this->dbname);
else {
this->db = QSqlDatabase::addDatabase("QSQLITE", this->dbname);
this->db.setDatabaseName(this->filename);
this->db.setPassword(this->password);
}
open();
}
private:
QSqlDatabase db;
QString dbname;
static QString filename;
static QString password;
};
I query the database in main(), before MainWindow's creation.
But during MainWindow's creation, the database destructor is called, and the database connection is closed and removed.
Afer that (in the ui initialization and any ui operations afterwards), all the database queries fail.
I notice that the ui's thread id and the main()'s thread id are exactly the same, to me they are the same thread.
I do not understand why the Datatbase object destructor is called in between (it seems like some old thread is destroyed, and some new thread is created with exactly the same thread id?).
If I just comment out the close and removeDatabase in the destructor, and everything works fine.
What is the exact reason for this?
Thanks.
thread_localobject gets destroyed when the thread that created it dies.Databasehas a none-trivial destructor that eventually releases the database handles. en.cppreference.com/w/cpp/language/rule_of_threethread_localto be destroyed. Did you try setting a breakpoint on the destructor -- maybe the stacktrace can provide an idea what might be going on? Also, I just googledQSqlDatabaseand learned that it can be copied, and I'm assumingQStringcan be copied anyway, so maybe you're making a copy somewhere and you're not even seeing the destructor call on thethread_localbut on the copy...auto db = Database::get()somewhere which creates a copy, you should make your class non-copyable