QThread und QWaitCondition (gelöst)

Alles rund um die Programmierung mit Qt
Antworten
MisterJ
Beiträge: 21
Registriert: 20. November 2008 12:21

QThread und QWaitCondition (gelöst)

Beitrag von MisterJ »

Hallo,

ich habe (mal wieder ;-) ) eine Frage zum QThread. Diesmal in der Kombination mit einer QWaitCondition.
Ich habe eine Worker-Klasse erstellt und wie in Link beschrieben in den QThread verschoben. In einer doWork()-Methode, die auf der EventLoop des Threads läuft, ist eine while-Schleife implementiert, an deren Ende ein QWaitCondition(&m_pMutex) steht.
Nun wollte ich die Worker-Klasse wieder aufwecken und habe in der Basisklasse ein Signal emittiert, dass eine Funktion in der Worker-Klasse aufruft, die den Thread wieder aufweckt. Diese wird aber im Basisklassen-Kontext ausgeführt und somit erscheint eine Fehlermeldung. Wenn ich diese Funktion einfach aufrufe (wie unten auskommentiert), dann kommt das gleiche. Ebenfalls das gleiche Resultat ergibt sich, wenn ich ein Signal in der Basisklasse emittiere, dass in der Worker-Klasse aufgefangen wird um selber ein Signal zu emittieren, dass auch vion der Worker-Klasse aufgefangen wird um den Thread aufzuwecken.

Wie also wecke ich einen Thread bzw. meine Worker-Klasse auf?

Vielen Dank,
Johannes

Threadtest_6.h

Code: Alles auswählen

#ifndef THREADTEST_6_H
#define THREADTEST_6_H

#include <QtGui/QMainWindow>
#include "ui_Threadtest_6.h"
#include "Worker.h"
#include <QMutex>
#include <QThread>

class Threadtest_6 : public QMainWindow
{
	Q_OBJECT

public:
	Threadtest_6(QWidget *parent = 0, Qt::WFlags flags = 0);
	~Threadtest_6();

private:
	Ui::Threadtest_6Class ui;
	QMutex * m_pMutex;
	QThread * m_pThread;
	Worker * m_pWorker;
signals:
	void signalDoWork(void);
	void signalWakeWorker(void);
private slots:
	void on_pushButton_StartThread_clicked(void);
	void slotWorkerData(QString szStatusMessage);
	void slotWorkerFinished(void);
};

#endif // THREADTEST_6_H
Threadtest_6.cpp

Code: Alles auswählen

#include "Threadtest_6.h"

Threadtest_6::Threadtest_6(QWidget *parent, Qt::WFlags flags)
	: QMainWindow(parent, flags)
{
	ui.setupUi(this);
}

Threadtest_6::~Threadtest_6()
{
}

void Threadtest_6::on_pushButton_StartThread_clicked()
{
	if(ui.pushButton_StartThread->text() == "Start")
	{
		ui.pushButton_StartThread->setText("Stop");
		m_pMutex = new QMutex;
		m_pThread = new QThread;
		m_pWorker = new Worker(m_pMutex);
		m_pWorker->moveToThread(m_pThread);
		m_pThread->start();

		connect(this, SIGNAL(signalDoWork()), m_pWorker, SLOT(slotDoWork()));
		connect(m_pWorker, SIGNAL(signalWorkerData(QString)), this, SLOT(slotWorkerData(QString)));
		connect(m_pWorker, SIGNAL(signalWorkerFinished()), this, SLOT(slotWorkerFinished()));
		connect(this, SIGNAL(signalWakeWorker()), m_pWorker, SLOT(slotWakeWorker()));
		connect(m_pWorker, SIGNAL(signalWake()), m_pWorker, SLOT(slotWake()));

		emit signalDoWork();
	}
	else
	{
		m_pWorker->m_bIsTracking = false;
	}
}

void Threadtest_6::slotWorkerData(QString szStatusMessage)
{
	ui.label_StatusMessage->setText(szStatusMessage);
	emit signalWakeWorker();
	//m_pWorker->slotWakeWorker();
}

void Threadtest_6::slotWorkerFinished(void)
{
	m_pThread->exit();
}
Worker.h

Code: Alles auswählen

#ifndef WORKER_H
#define WORKER_H

#include <QObject>
#include <time.h>
#include <QWaitCondition>
#include <QMutex>

class Worker :
	public QObject
{
	Q_OBJECT
public:
	Worker(QMutex * pMutex);
	~Worker(void);
	bool m_bIsTracking;
private:
	QMutex * m_pMutex;
	QWaitCondition m_WaitCondition;
signals:
	void signalWorkerFinished(void);
	void signalWorkerData(QString szStatusMessage);
	void signalWake(void);
public slots:
	void slotDoWork(void);
	void slotWakeWorker(void);
	void slotWake(void);
};

#endif
Worker.cpp

Code: Alles auswählen

#include "Worker.h"

Worker::Worker(QMutex * pMutex)
{
	m_pMutex = pMutex;
	m_bIsTracking = true;
}

Worker::~Worker(void)
{
}

void Worker::slotDoWork(void)
{
	srand( (unsigned)time( NULL ) );
	while(m_bIsTracking)
	{
		emit signalWorkerData(QString::number((rand()%1000) + 1));
		m_WaitCondition.wait(m_pMutex); 
	}
	emit signalWorkerFinished();
}

void Worker::slotWakeWorker()
{
	//m_WaitCondition.wakeAll();
	emit signalWake();
}

void Worker::slotWake(void)
{
	m_WaitCondition.wakeAll();
}
Dateianhänge
Threadtest_6.rar
(2.27 KiB) 135-mal heruntergeladen
Zuletzt geändert von MisterJ am 7. September 2010 14:24, insgesamt 1-mal geändert.
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Das Spiel hatten wir doch erst... m_pWorker lebt noch im Hauptthread. Also werden alle Verbindungen von MainWindow nach m_pWorker im Main-Thread abgehandelt.
Des weiteren würde ich von QThread ableiten und dort meinen Worker instanziieren (in run()). So sieht das irgendwie unübersichtlich aus.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
MisterJ
Beiträge: 21
Registriert: 20. November 2008 12:21

Beitrag von MisterJ »

Christian81 hat geschrieben:m_pWorker lebt noch im Hauptthread
Ich dachte mit

Code: Alles auswählen

m_pWorker->moveToThread(m_pThread);
ist das gerade nicht mehr der Fall.

Mir ist klar, dass ich aus meiner Basisklasse die QWaitCondition, die ich in einem anderen Thread bzw. in der Worker-Klasse gestartet habe, nicht per normalem Fubktionsaufruf wieder aufwecken kann. Ich hatte aber gehofft, dass es mit Signals und Slots doch irgendwie möglich wäre. Gibt es also einen anderen Weg um das zu erreichen?
Christian81 hat geschrieben:Des weiteren würde ich von QThread ableiten und dort meinen Worker instanziieren (in run()). So sieht das irgendwie unübersichtlich aus.
In dem Beitrag, den ich oben verlinkt habe wird gesagt, dass es der elegantere Weg ist. Ich gebe zu, dass es für mein Minimalbeispiel etwas zu überladen ist, aber es steckt ja in Wirklichkeit eine komplexere Implementierung dahinter ;-)

Viele Grüße,
Johannes
MisterJ
Beiträge: 21
Registriert: 20. November 2008 12:21

Beitrag von MisterJ »

Es hatte nichts mit Thread-Kontext oder dergleichen zu tun.
Es fehlte ein

Code: Alles auswählen

QMutexLocker locker(m_pMutex);
am Anfang der while-Schleife in der Worker-Klasse.

Viele Grüße
Johannes
Antworten