QSqlDatabase + multiple threads
-
Hi, I'm trying to allow mutiple threads to perform reads from my database. From what I understand from the documentation (http://doc.qt.io/qt-5/qsqldatabase.html), this should be possible as long as each thread creates, uses and maintains it's own connection. Here, I have a launch 3 threads, and on a timer they will access each database.
DataBaseConnector.h
#include <QObject> #include <QtSQL> class DatabaseConnector : public QObject { Q_OBJECT public: DatabaseConnector(int id); ~DatabaseConnector(); private: int myID; QSqlDatabase _db; QSqlQuery query; QTimer *timer; QString conName; public slots: void run(); void tick(); signals: void sendText(QString text); };
.cpp
#include "DatabaseConnector.h" DatabaseConnector::DatabaseConnector(int id) { myID = id; } DatabaseConnector::~DatabaseConnector() { //TO-DO CLEANUP } void DatabaseConnector::run() { conName = QStringLiteral("_conSldb_") + QString::number(myID); //Create a connection with a unique name _db = QSqlDatabase::addDatabase("QMYSQL", conName); _db.setHostName("localhost"); //Go to local host _db.setDatabaseName("world"); //Open the "world" schema _db.setUserName("xxxxx"); _db.setPassword("xxxxx"); bool ok = _db.open(); if (ok) { timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(tick())); timer->start(1000); } else { qDebug() << "failed to open db at thread_id: " + myID; } } void DatabaseConnector::tick() { QSqlQuery query(QSqlDatabase::database(conName)); query.exec("SELECT Language, CountryCode FROM countrylanguage WHERE Language = 'Dutch'"); while (query.next()) { QString name = query.value(1).toString(); //TODO - emit to gui //emit sendText(name); } }
main
#include <QtSQL> #include "DatabaseConnector.h" #include <qtconcurrentrun.h> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QThread *thread1 = new QThread; QThread *thread2 = new QThread; QThread *thread3 = new QThread; DatabaseConnector* db1 = new DatabaseConnector(1); DatabaseConnector* db2 = new DatabaseConnector(2); DatabaseConnector* db3 = new DatabaseConnector(3); db1->moveToThread(thread1); QObject::connect(thread1, SIGNAL(started()), db1, SLOT(run())); db2->moveToThread(thread2); QObject::connect(thread2, SIGNAL(started()), db2, SLOT(run())); db3->moveToThread(thread3); QObject::connect(thread3, SIGNAL(started()), db3, SLOT(run())); thread1->start(); thread2->start(); thread3->start(); return a.exec(); }
This setup works with one thread, but with 2+ I get:
"QObject::moveToThread: Current thread (0xb9b648) is not the object's thread (0xb9c0b0).
Cannot move to target thread (0xb8f298)".This typically happens around the "bool ok = _db.open();" line within the run(). Cleanup issues aside, I cannot see anything wrong with the thread setup in the main.
Could anyone please offer any insight into my issues?
UPDATE:
lastError() returns "Unknown MySQL server host 'localhost'". One thread has no problem finding it, the others fail to know it exists. Yet the issue that prints is "QObject::moveToThread: Current thread (0xb9b648) is not the object's thread (0xb9c0b0)..."
-
Hi, I'm trying to allow mutiple threads to perform reads from my database. From what I understand from the documentation (http://doc.qt.io/qt-5/qsqldatabase.html), this should be possible as long as each thread creates, uses and maintains it's own connection. Here, I have a launch 3 threads, and on a timer they will access each database.
DataBaseConnector.h
#include <QObject> #include <QtSQL> class DatabaseConnector : public QObject { Q_OBJECT public: DatabaseConnector(int id); ~DatabaseConnector(); private: int myID; QSqlDatabase _db; QSqlQuery query; QTimer *timer; QString conName; public slots: void run(); void tick(); signals: void sendText(QString text); };
.cpp
#include "DatabaseConnector.h" DatabaseConnector::DatabaseConnector(int id) { myID = id; } DatabaseConnector::~DatabaseConnector() { //TO-DO CLEANUP } void DatabaseConnector::run() { conName = QStringLiteral("_conSldb_") + QString::number(myID); //Create a connection with a unique name _db = QSqlDatabase::addDatabase("QMYSQL", conName); _db.setHostName("localhost"); //Go to local host _db.setDatabaseName("world"); //Open the "world" schema _db.setUserName("xxxxx"); _db.setPassword("xxxxx"); bool ok = _db.open(); if (ok) { timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(tick())); timer->start(1000); } else { qDebug() << "failed to open db at thread_id: " + myID; } } void DatabaseConnector::tick() { QSqlQuery query(QSqlDatabase::database(conName)); query.exec("SELECT Language, CountryCode FROM countrylanguage WHERE Language = 'Dutch'"); while (query.next()) { QString name = query.value(1).toString(); //TODO - emit to gui //emit sendText(name); } }
main
#include <QtSQL> #include "DatabaseConnector.h" #include <qtconcurrentrun.h> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QThread *thread1 = new QThread; QThread *thread2 = new QThread; QThread *thread3 = new QThread; DatabaseConnector* db1 = new DatabaseConnector(1); DatabaseConnector* db2 = new DatabaseConnector(2); DatabaseConnector* db3 = new DatabaseConnector(3); db1->moveToThread(thread1); QObject::connect(thread1, SIGNAL(started()), db1, SLOT(run())); db2->moveToThread(thread2); QObject::connect(thread2, SIGNAL(started()), db2, SLOT(run())); db3->moveToThread(thread3); QObject::connect(thread3, SIGNAL(started()), db3, SLOT(run())); thread1->start(); thread2->start(); thread3->start(); return a.exec(); }
This setup works with one thread, but with 2+ I get:
"QObject::moveToThread: Current thread (0xb9b648) is not the object's thread (0xb9c0b0).
Cannot move to target thread (0xb8f298)".This typically happens around the "bool ok = _db.open();" line within the run(). Cleanup issues aside, I cannot see anything wrong with the thread setup in the main.
Could anyone please offer any insight into my issues?
UPDATE:
lastError() returns "Unknown MySQL server host 'localhost'". One thread has no problem finding it, the others fail to know it exists. Yet the issue that prints is "QObject::moveToThread: Current thread (0xb9b648) is not the object's thread (0xb9c0b0)..."
-
conName = "_conSldb_" + myID;
does not do what you think it does. useconName = QStringLiteral("_conSldb_") + QString::number(myID);
-
Hi,
Why are you keeping member variables fro query and _db ?
You don't need them.
-
Hello. You're right. I'm still getting accustomed to the system and figuring this out.
Small update: lastError() returns "Unknown MySQL server host 'localhost'". One thread has no problem finding it, the others fail to know it exists. Yet the issue that prints is "QObject::moveToThread: Current thread (0xb9b648) is not the object's thread (0xb9c0b0)..."
-
One thing to take into account is that everything that is happening at construction time happens in the main thread thus the object created there are created in the main thread.. When moving your worker to another thread only objects which have the worker as parent will get moved with it. Then what you create in your DatabaseConnector run function will have affinity with the thread where you moved the worker to.