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)..."



  • conName = "_conSldb_" + myID; does not do what you think it does. use conName = QStringLiteral("_conSldb_") + QString::number(myID);



  • @VRonin Thanks for the suggestion, it certainly ensures the parameter is formatted. I've amended the line but there's no change to functionality.



  • before bool ok = _db.open(); could you check what _db.isOpen(); returns?



  • @VRonin said in QSqlDatabase + multiple threads:

    Always false, maybe because I haven't called open() yet.

    If I call after, it returns true if is also "ok" is true. If ok is false, it also returns false.


  • Lifetime Qt Champion

    Hi,

    Why are you keeping member variables fro query and _db ?

    You don't need them.



  • @SGaist

    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)..."


  • Lifetime Qt Champion

    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.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.