Threads funktionieren nciht immer

Alles rund um die Programmierung mit Qt
C167
Beiträge: 105
Registriert: 9. Februar 2008 20:30

Threads funktionieren nciht immer

Beitrag von C167 »

Tagchen,
ich hab hier eine Klasse, die Daten aus einer Datenbank laedt. Dazu rufe ich den Slot "getData" ueber Queued connections auf. So, an sich funktioniert alles, aber eben nicht immer. Ich hab ein paar Debuggingausgaben eingebaut, die im allgemeinen wie folgt aussehen:

Code: Alles auswählen

get:  "splashes"   1
get:  "splashes"   2
run:  "splashes"   1
fin:  "splashes"   1
run:  "splashes"   2
get:  "splashes"   3
fin:  "splashes"   2
run:  "splashes"   3
get:  "img_images"   1
run:  "img_images"   1
fin:  "splashes"   3
fin:  "img_images"   1
Nun kommt es aber sporadisch vor, dass eines oder zwei der Querys offenbar nicht ganz durchlaufen, jedenfalls fehlt am Ende eine "fin:" Zeile und das entsprechende Signal wird nicht aufgerufen.
Header:

Code: Alles auswählen

class BinaryLoader : public QThread
{
		Q_OBJECT
	public:
		BinaryLoader (  );
		~BinaryLoader ( );
	public slots:
		void getData ( const QString&, const int& );
	signals:
		void dataLoaded ( const int&, const QByteArray& );
	protected:
		void run();
		QString tableName;
		int id;
	private:
		QMutex mutex;
};
Source:

Code: Alles auswählen

BinaryLoader::BinaryLoader ( ) : QThread ( )
{
}

BinaryLoader::~BinaryLoader()
{
}

void BinaryLoader::getData ( const QString &tableName, const int &id )
{
	qDebug() << "get: " << tableName << " " << id;
	mutex.lock();
	this->tableName = tableName;
	this->id = id;
	mutex.unlock();
	start();
}

void BinaryLoader::run()
{
	mutex.lock();
	qDebug() << "run: " << tableName << " " << id;
	QString _tableName = this->tableName;
	int _id = this->id;
	
	qsrand ( QTime::currentTime().msec() );
	QString connectionName = QString ( "thread_%1_%2_%3" ).arg ( qrand() ).arg ( _tableName ).arg ( _id );
	{
		QSqlDatabase db = QSqlDatabase::addDatabase ( "QSQLITE", connectionName );
		db.setDatabaseName ( QSqlDatabase::database().databaseName () );
		db.open();
		bool good = true;
		QSqlQuery query ( QSqlDatabase::database ( connectionName ) );
		query.prepare ( QString ( "SELECT data FROM %1 WHERE id = :id" ).arg ( tableName ) );
		query.bindValue ( ":id", id );
		if ( !query.exec() ) good = false;
		if ( !query.next() ) good = false;
		if ( good )
		{
			emit dataLoaded ( id, query.value ( 0 ).toByteArray ( ) );
		}
		query.clear();
	}
	QSqlDatabase::removeDatabase ( connectionName );
	qDebug() << "fin: " << tableName << " " << id;
	mutex.unlock();
}
Verbunden wurde das Hauptprogramm und die Thread Klasse wie folgt:

Code: Alles auswählen

connect ( this,   SIGNAL ( loadImage ( QString, int ) ),     loader, SLOT ( getData ( QString, int ) ),    Qt::QueuedConnection );
connect ( loader, SIGNAL ( dataLoaded ( int, QByteArray ) ), this,   SLOT ( display ( int, QByteArray ) ), Qt::QueuedConnection );
Direkt nach dem connect werden dabei sofort drei Threads gestartet:

Code: Alles auswählen

emit loadImage ( QString ( "splashes" ), 1 );
emit loadImage ( QString ( "splashes" ), 2 );
emit loadImage ( QString ( "splashes" ), 3 );
Was mich sutzig macht ist, dass der Thread offenbar ohne einen Klagelaut stirbt oder einfach die Arbeit einstellt.
C167
Beiträge: 105
Registriert: 9. Februar 2008 20:30

Beitrag von C167 »

nachtrag: waerend auf Linux nur manchmal einer und sehr selten zwei Threads sterben, fallen unter Windows meistens zwei aus

hab ich mich da generell verbastelt? Bin fuer jede Hilfe dankbar
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Ich würde es erst einmal ohne die SQL-Querys testen. Vielleicht kommt der DB-Treiber durcheinander wenn so viele Verbindungen von verschiedenen Threads kommen.
Ein Debugger um zu schauen wo die Threads hängen wäre auch nicht schlecht.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
nando
Beiträge: 321
Registriert: 28. Oktober 2004 13:16

Beitrag von nando »

Hi,
siehe doku:

http://doc.trolltech.com/4.4/threads.ht ... -sql-modul

A connection can only be used from within the thread that created it. Moving connections between threads or creating queries from a different thread is not supported.
C167
Beiträge: 105
Registriert: 9. Februar 2008 20:30

Beitrag von C167 »

Hm, ich komm mit dem gdb noch nicht so zurecht... deshalb bin ich andrs vorgegangen: jede Zeile erhielt ne ausgabe ;)
Dabei ist mir aufgefallen, dass z.b. das Signal Nr 1 ausgeloest wird (slot aufgerufen), direkt drauf nummer 2. Dann started Thread 1 und wird komplett abgearbeitet. Anschliessend wird Signal 3 getriggert, der Thread aber nichtmal gestartet.

Daraus schliesse ich momentan, dass es an der Falschen Verwendung des Mutexes liegt. Die sind extremes Neuland fuer mich ;)
C167
Beiträge: 105
Registriert: 9. Februar 2008 20:30

Beitrag von C167 »

@nando: ich erstelle ja in jedem Thread eine eigene Verbindung, die nur innerhalb von run() existiert
C167
Beiträge: 105
Registriert: 9. Februar 2008 20:30

Beitrag von C167 »

sooo, ich hab jetzt das Threading mal abgeschalten (einfach run() anstelle von start() gemacht), und da geht es, klar, kommt sich ja nichts ins gehege. Kann man da evtl was mit der QWaitCondition machen?
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

C167 hat geschrieben:Kann man da evtl was mit der QWaitCondition machen?
Dann brauchst Du auch keine Threads... :roll:
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
C167
Beiträge: 105
Registriert: 9. Februar 2008 20:30

Beitrag von C167 »

hm... wie gesagt, das is neuland fuer mich ;)
ich hab ein Beispiel, das Threads und wait conditions nutzt, und zwar den "photoflow" auf code.google.com
Vorteil ware eben dass die GUI bei Threads nicht blokieren wuerde, wenn man ein einzelnes Bild aus der Datenbank laedt, sondern nur solange die Skalierung dauert...
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Wenn Du nach dem fetch natürlich noch was machst, dann ja.
Trotzdem würde ich da wohl eher einen globalen QMutex nehmen als eine QWaitCondition. Aber das ist deine Sache.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
C167
Beiträge: 105
Registriert: 9. Februar 2008 20:30

Beitrag von C167 »

globaler mutex? was ist der Unterschied zu meiner Loesung dabei?
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Da dein Mutex (in deinem Beispiel) nicht static ist, bekommt jeder Thread einen eigenen QMutex.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
C167
Beiträge: 105
Registriert: 9. Februar 2008 20:30

Beitrag von C167 »

aeh? aber alle threads haben doch auf die mutex variable zugriff, warum sollte da jeder thread ein eigenes Mutex-objekt bekommen?
Dass Threads die von einem anderem BinaryLoader-Objekt erzeugt werden einen eigenen Mutex haben, ist ja klar, aber ich rufe ja den getData Slot 3mal direkt hintereinander mit demselben Objekt auf
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Lest noch mal die Doku zu dem SQL Modul bitte ...
Also ich habs so verstanden, das alle SQL Befehle aus dem selben thread kommen muessen wo auch die COnnection erstellt wurde. Alles andere waere undefiniertes verhalten ....

@C167
fuer dich wuerde das heissen, du musst / kannst deine SQL zugriffe schon vom gui thread entkoppeln, aber muesstest alle aufrufe die auf die DB gehen wieder auf den einen SQL thread mappen ....
die waitkondition koenntest nutzen, um den SQL thread loslaufen zu lassen ...
Trotzdem brauchtest vielleichtne art queue wo "kommandos" vom Gui thread entkoppelst, und die muesstest dann schuetzen , das geht mit nem mutex ...

nen mutex fuer die DB waer sinnlos, weil wirklich nur 1 thread drauf duerft ...

Ciao ...
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

C167 hat geschrieben:aeh? aber alle threads haben doch auf die mutex variable zugriff, warum sollte da jeder thread ein eigenes Mutex-objekt bekommen?
Wenn du jedes Mal ein neues Thread-Objekt erzeugst wird wohl auch jedes mal ein neuer Mutex erzeugt, oder?
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Antworten