0

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.

7
  • 1
    Why such a hack in the first place? Simply use QSqlDatabase::addDatabase() and QSqlDatabase::database() in the first place. Also you don't show the usage of your class so we don't see where the destructor is called -> please provide a minimal, compilable example or even better - use the class Qt provided by you as nothing above is needed at all. Commented Jun 16, 2024 at 9:16
  • 2
    The thread_local object gets destroyed when the thread that created it dies. Commented Jun 16, 2024 at 9:17
  • 1
    This is not the minimum reproducible sample. But I can see a half baked thread singleton pattern. I see a possibility for violation of rule 350; because Database has a none-trivial destructor that eventually releases the database handles. en.cppreference.com/w/cpp/language/rule_of_three Commented Jun 16, 2024 at 9:43
  • 1
    On first glance, there appears to be no reason for the thread_local to 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 googled QSqlDatabase and learned that it can be copied, and I'm assuming QString can be copied anyway, so maybe you're making a copy somewhere and you're not even seeing the destructor call on the thread_local but on the copy... Commented Jun 16, 2024 at 10:04
  • 1
    At a guess you have a auto db = Database::get() somewhere which creates a copy, you should make your class non-copyable Commented Jun 16, 2024 at 10:09

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.