Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Crash in qsqlite module



  • Hello,
    maybe somebody can help me or give me some hints what i can do to avoid such crashes ?

    Bildschirmfoto 2020-09-08 um 08.19.40.png

    What im doing:

    • Each Image is stored via an unique hash and the image data in my sqlite database
    • When trying to display the image (via GraphicItem) the data is loaded from the sqlite database with the image hash
    • This all happens Multithreaded. So for each Loading attempt an own sql connection is made because QSqlDatabase can only be accessed in the thread being created
    • The crash is not reproducible on my machine

    I am using Qt Version 5.12.9.


  • Lifetime Qt Champion

    Hi,

    How are you setting up the database connection ?

    Might be unrelated but how are you getting the image back to your QGraphicsItem ?



  • bool DbFile::requestDb(QSqlDatabase &db) const {
    
        // mkh20130206: QSqlDatabase can only be accessed in the thread being created
        int tid = _threadId();
        QString connectionName = QString("%1-%2").arg(mFileName).arg(tid);
    
        bool retVal = false;
        if (QSqlDatabase::contains(connectionName)) {
            db = QSqlDatabase::database(connectionName);
            retVal = db.isValid() && db.isOpen();
        } else {
            db = QSqlDatabase::addDatabase("QSQLITE", connectionName);
            if (db.isValid()) {
                db.setDatabaseName(mFileName);
                retVal = db.open();
                if (retVal) {
                    // store created db connection for later destroy
                    QMutexLocker _accessLock(&mConnectionsLock);
                    mConnections << connectionName;
                }
            }
        }
        return retVal;
    }
    

    That's the code for the creation of the database connection.

    The Image is sent back as QByteArray. After that is is used for creating QPixmap or QImage (depends on the use case):

    data = q.value(0).toByteArray();
    

  • Lifetime Qt Champion

    Is that requestDb method called in a method that runs in the thread using the connection ?



  • Yes. The requestDb Method ensures that a connection is used which is created only for that Thread.
    Therefore a unique thread id is generated and used as connection name. Look at the following line.

    int tid = _threadId();
    QString connectionName = QString("%1-%2").arg(mFileName).arg(tid);
    
    static QHash<QThread*, int> _threadIds;
    static int _threadCounter;
    static QMutex _threadIdLock(QMutex::Recursive);
    
    int _threadId() {
        QMutexLocker _accessLock(&_threadIdLock);
        QThread *curThread = QThread::currentThread();
        if (!_threadIds.contains(curThread)) {
            if (qApp->thread() == curThread) {
                _threadIds[curThread] = 0;
            } else {
                _threadIds[curThread] = ++_threadCounter;
            }
        }
        return _threadIds[curThread];
    }
    

  • Qt Champions 2019

    SQlite is not threadsafe by default: https://sqlite.org/threadsafe.html
    Also Qt does not compile the sqlite plugin with SQLITE_THREADSAFE



  • Is there any possibillity to get this working for multi threaded applications ?


  • Qt Champions 2019

    @euchkatzl Compile the qt sql plugin with the define I mentioned and activate it as described in the link I gave you.



  • Thank you. I will try this


Log in to reply