Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Sqlite Multithread
Forum Updated to NodeBB v4.3 + New Features

Sqlite Multithread

Scheduled Pinned Locked Moved Unsolved General and Desktop
6 Posts 4 Posters 747 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • piervalliP Offline
    piervalliP Offline
    piervalli
    wrote on last edited by
    #1

    Hi,

    With Sqlite and multithread we need to write syncronized.
    First i haved improved the multithread with "PRAGMA journal_mode=WAL;".
    For synchronization I have declared a QMutex globalMutex witch is used on write.

    static auto func = [](int rows,int offset){
            QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE",QString::number(offset));
            db.setDatabaseName("mydatabase.db"); // Replace with your database name
            db.setConnectOptions(QLatin1String("QSQLITE_ENABLE_REGEXP=1;QSQLITE_BUSY_TIMEOUT=10000"));
            if (!db.open()) {
                qDebug() << "Database connection failed";
            }
            globalMutex.lock();
            db.transaction();
            while(rows>0){
                --rows;
                ++offset;
                QSqlQuery query(db);
                if(!query.prepare("insert into product(id,description) values(:id,:description)")){
                    qCritical() << query.lastError();
                }
                query.bindValue(":id",offset);
                query.bindValue(":description",offset);
    
                if(!query.exec()){
                    qCritical() << query.lastError().databaseText();
                }
    
                if(!query.exec("update product set description ='1' where id =1;")){
                    qCritical() << query.lastError();
                }
            }
            db.commit();
            globalMutex.unlock();
        };
        QtConcurrent::run(func,300000,0);
        QtConcurrent::run(func,300000,600001);
    

    The code run without errors. is it correcy use of global QMutex?

    Thanks

    C 1 Reply Last reply
    0
    • piervalliP piervalli

      Hi,

      With Sqlite and multithread we need to write syncronized.
      First i haved improved the multithread with "PRAGMA journal_mode=WAL;".
      For synchronization I have declared a QMutex globalMutex witch is used on write.

      static auto func = [](int rows,int offset){
              QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE",QString::number(offset));
              db.setDatabaseName("mydatabase.db"); // Replace with your database name
              db.setConnectOptions(QLatin1String("QSQLITE_ENABLE_REGEXP=1;QSQLITE_BUSY_TIMEOUT=10000"));
              if (!db.open()) {
                  qDebug() << "Database connection failed";
              }
              globalMutex.lock();
              db.transaction();
              while(rows>0){
                  --rows;
                  ++offset;
                  QSqlQuery query(db);
                  if(!query.prepare("insert into product(id,description) values(:id,:description)")){
                      qCritical() << query.lastError();
                  }
                  query.bindValue(":id",offset);
                  query.bindValue(":description",offset);
      
                  if(!query.exec()){
                      qCritical() << query.lastError().databaseText();
                  }
      
                  if(!query.exec("update product set description ='1' where id =1;")){
                      qCritical() << query.lastError();
                  }
              }
              db.commit();
              globalMutex.unlock();
          };
          QtConcurrent::run(func,300000,0);
          QtConcurrent::run(func,300000,600001);
      

      The code run without errors. is it correcy use of global QMutex?

      Thanks

      C Offline
      C Offline
      ChrisW67
      wrote on last edited by
      #2

      @piervalli You could use QMutexLocker in place of explicit lock()/unlock() calls.

      Christian EhrlicherC 1 Reply Last reply
      0
      • C ChrisW67

        @piervalli You could use QMutexLocker in place of explicit lock()/unlock() calls.

        Christian EhrlicherC Offline
        Christian EhrlicherC Offline
        Christian Ehrlicher
        Lifetime Qt Champion
        wrote on last edited by
        #3

        I don't see why there is a mutex needed at all - what's the goal for it?

        Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
        Visit the Qt Academy at https://academy.qt.io/catalog

        piervalliP 1 Reply Last reply
        0
        • Christian EhrlicherC Christian Ehrlicher

          I don't see why there is a mutex needed at all - what's the goal for it?

          piervalliP Offline
          piervalliP Offline
          piervalli
          wrote on last edited by
          #4

          @Christian-Ehrlicher
          With Sqlite we can write only one time to avoid the message error "database locked", we need to synchronize it.

          KenAppleby 0K 1 Reply Last reply
          0
          • piervalliP piervalli

            @Christian-Ehrlicher
            With Sqlite we can write only one time to avoid the message error "database locked", we need to synchronize it.

            KenAppleby 0K Offline
            KenAppleby 0K Offline
            KenAppleby 0
            wrote on last edited by
            #5

            @piervalli said in Sqlite Multithread:

            is it correcy use of global QMutex?

            Well, it's not wrong, but it is effectively serialising your two calls to func, and there is nothing to be gained by using QtConcurrent.

            You can let SQLITE do this work for you. See:
            https://www.sqlite.org/c3ref/c_config_covering_index_scan.html

            As you are using two different database connections (one named "0", the other "600001") they can be accessed safely from separate threads, one thread per connection, without mutexes, if you configure your connection options with "SQLITE_CONFIG_MULTITHREAD" or "SQLITE_CONFIG_SERIALIZED".

            Whether this gains you any performance or just pushes the serialisation down the stack into the sqlite driver I don't know.

            piervalliP 1 Reply Last reply
            1
            • KenAppleby 0K KenAppleby 0

              @piervalli said in Sqlite Multithread:

              is it correcy use of global QMutex?

              Well, it's not wrong, but it is effectively serialising your two calls to func, and there is nothing to be gained by using QtConcurrent.

              You can let SQLITE do this work for you. See:
              https://www.sqlite.org/c3ref/c_config_covering_index_scan.html

              As you are using two different database connections (one named "0", the other "600001") they can be accessed safely from separate threads, one thread per connection, without mutexes, if you configure your connection options with "SQLITE_CONFIG_MULTITHREAD" or "SQLITE_CONFIG_SERIALIZED".

              Whether this gains you any performance or just pushes the serialisation down the stack into the sqlite driver I don't know.

              piervalliP Offline
              piervalliP Offline
              piervalli
              wrote on last edited by piervalli
              #6

              @KenAppleby-0

              In the documentations of Qt

              https://doc.qt.io/qt-5/sql-driver.html#qsqlite

              SQLite has some restrictions regarding multiple users and multiple transactions. If you try to read/write on a resource from different transactions, your application might freeze until one transaction commits or rolls back. The Qt SQLite driver will retry to write to a locked resource until it runs into a timeout (see QSQLITE_BUSY_TIMEOUT at QSqlDatabase::setConnectOptions()).

              In the Sqlite documentation
              https://www.sqlite.org/c3ref/c_config_covering_index_scan.html#sqliteconfigserialized

              SQLITE_CONFIG_SERIALIZED
              There are no arguments to this option. This option sets the threading mode to Serialized. In other words, this option enables all mutexes including the recursive mutexes on database connection and prepared statement objects. In this mode (which is the default when SQLite is compiled with SQLITE_THREADSAFE=1)

              Final considerations
              Sqlite is builded with flag THREADSAFE=1 we can check with the query "PRAGMA compile_options;", all mutex are enabled and for default configuration thread mode is SQLITE_CONFIG_SERIALIZED. Until the timeout Sqlite retry to write. For my case I changed to timeout to 5 minute i haved limited the transaction to strictly necessary, because the transaction locks all.
              In addition PRAGMA journal_mode=WAL; is useful for multithreading.

              The global QMutex is not necessary.

              1 Reply Last reply
              0

              • Login

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • Users
              • Groups
              • Search
              • Get Qt Extensions
              • Unsolved