Also vorweg zu meinem Anliegen:
In einem SW-Projekt mit 5 Leuten bearbeiten wir eine etwas größere Aufgabe. Mein Teil dabei ist so der "Kern" der Sache. Der die Objekte der Anderen erzeugt und handelt.
Geplant ist es so: Der Mainthread, der mit dem Prozess erzeugt wird, ist für die GUI, also das man dort die Button's usw. bedienen kann und es gibt eine QThread abgeleitete Klasse, die als WorkerThread (mit eigener Eventloop) fungiert. Dieser bekommt von der GUI, oder anderen Objekten meiner Kollegen Jobs in einen Puffer geladen. Der Workerthread schaut mit einem eigenem QTimer immer wieder nach, ob dieser Puffer voll ist, wenn ja, bearbeitet er den Job...
Das funktioniert soweit auch gut, aber habe den Vedacht, dass es irgendwie alles in dem Mainthread ausgeführt wird.
Deswegen habe ich mir ein neues Bsp-Projekt erzeugt, was unabhängig vom laufendem Projekt ist und habe dazu Fragen an euch, bzw. brauch eure Hilfe, um das QThreading auch richtig verstanden zu haben:
Hier die main.cpp:
Es wird ein RF_Core Objekt erzeugt und gestartet. Dann mit app.exec() in die Eventloop gewechselt
Code: Alles auswählen
#include "RF_Core.h"
#include <QtCore>
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
RF_Core core;
core.startCore();
qDebug("MAIN METHOD:: GOING INTO EVENTLOOP OF MAINTHREAD");
return app.exec();
}
Code: Alles auswählen
#ifndef RF_CORE_H
#define RF_CORE_H
#include <QObject>
#include <QTimer>
#include "RF_Thread.h"
class RF_Core : public QObject
{
Q_OBJECT
private:
QTimer * mTimer;
RF_Thread * mThread1;
int mSwitch;
public:
void startCore();
public slots:
void timerSlot();
signals:
void signalTask2();
void signalTask3();
};
#endif
Hier die *.cpp des RF_Core
Code: Alles auswählen
#include "RF_Core.h"
#include "RF_Core_Server.h"
void RF_Core::startCore()
{
qDebug("Core is running");
this->mSwitch = 0;
this->mTimer = new QTimer();
QObject::connect(this->mTimer, SIGNAL(timeout()), this, SLOT(timerSlot()));
this->mTimer->setSingleShot(true);
this->mTimer->start(3500);
this->mThread1 = new RF_Thread(this->parent());
QObject::connect(this, SIGNAL(signalTask2()), this->mThread1, SLOT(task2()), Qt::QueuedConnection);
this->mThread1->start(QThread::NormalPriority);
// signal3 mit signal3 des threads verbinden:
QObject::connect(this, SIGNAL(signalTask3()), this->mThread1, SIGNAL(signalTask3()), Qt::QueuedConnection);
}
void RF_Core::timerSlot()
{
qDebug("void RF_Core::timerSlot() >> MAINTHREAD <<");
if(this->mThread1->isRunning())
qDebug("Thread is running...");
else
qDebug("Thread is NOT running...");
if (this->mSwitch == 0)
{
this->mSwitch++;
qDebug(">>> mSwitch is 0 <<<");
qDebug("call the task1 method of thread...");
this->mThread1->task1();
qDebug("try to start the timer again; 3sec");
this->mTimer->start(3000);
}
else
if (this->mSwitch == 1)
{
this->mSwitch++;
qDebug(">>> mSwitch is 1 <<<");
qDebug("emit signal of task2");
emit this->signalTask2();
qDebug("try to start the timer again; 1,5sec");
this->mTimer->start(1500);
}
else
if (this->mSwitch == 2)
{
this->mSwitch = 0;
qDebug(">>> mSwitch is 2 <<<");
qDebug("emit signal to emit thread- signalTask3()");
emit this->signalTask3();
qDebug("try to start the timer again; 2,222sec");
this->mTimer->start(2222);
}
}
Code: Alles auswählen
#ifndef RF_THREAD_H_
#define RF_THREAD_H_
#include <QThread>
#include <QTimer>
class RF_Thread : public QThread
{
Q_OBJECT
private:
int mCount; // einfacher Zähler
QTimer *mTimer;
// einfache Zähler der einzelnen "Aufgaben"
int mTask1;
int mTask2;
int mTask3;
public:
RF_Thread(QObject* parent = 0);
void run();
private slots:
void internalTask();
public slots:
void task1();
void task2();
void task3();
signals:
void startTimer(int);
void stopTimer();
void signalTask3(); // in run() wird ein connect auf den slot task3() gemacht
};
#endif /*RF_THREAD_H_*/
Die task1, task2, task3, internalTask machen keine besonderen Aufgaben. Hauptsächlich geht es darum, dass der QTimer ma an/ausgeschaltet wird und man qDebug's der angestoßenen Slot's erhält
Hier der *.cpp des RF_Thread
Code: Alles auswählen
#include "RF_Thread.h"
RF_Thread::RF_Thread(QObject* parent)
: QThread(parent)
{
this->mCount = 0;
this->mTask1 = 0;
this->mTask2 = 0;
this->mTask3 = 0;
}
void RF_Thread::run()
{
qDebug(" void RF_Thread::run()");
qDebug(" Create new Timer & connect it");
this->mTimer = new QTimer();
QObject::connect(mTimer, SIGNAL(timeout()), this, SLOT(internalTask()));
QObject::connect(this, SIGNAL(startTimer(int)), this->mTimer, SLOT(start(int)));
QObject::connect(this, SIGNAL(stopTimer()), this->mTimer, SLOT(stop()));
// eigenes Signal wird mit eigenem Slot verbunden
QObject::connect(this, SIGNAL(signalTask3()), this, SLOT(task3()));
this->exec();
}
void RF_Thread::internalTask()
{
qDebug(" void RF_Thread::internalTask()");
qDebug(" >> Count: %i, Task1: %i, Task2: %i, Task3: %i", this->mCount, this->mTask1,
this->mTask2, this->mTask3);
}
void RF_Thread::task1() // wird "normal" von RF_Core Object aufgerufen
{
qDebug(" void RF_Thread::task1()");
this->mCount++;
this->mTask1++;
qDebug("emit stopTimer()");
emit this->stopTimer(); // stoppe den eigenen QTimer
}
void RF_Thread::task2() // wird emitiert
{
qDebug(" void RF_Thread::task2()");
this->mCount++;
this->mTask2++;
if(!this->mTimer->isActive())
{
qDebug("emit startTimer(500)");
emit this->startTimer(500); // starte eigenen QTimer
}
}
void RF_Thread::task3() // wird von außen mit Signal über das eigene Signal emitiert
{
qDebug(" void RF_Thread::task3()");
this->mCount++;
this->mTask3++;
//while(1){}; // Annahme: Thread (this) wäre ausgelastet, aber es sollte eigentlich der Main- Thread
// weiterlaufen?! Also qDebug(..)'s ausgeben..
}
So, das läuft soweit ohne Probleme.
Jetzt geht's los:
------------------------------------------------------------------------------------
In dem Qt4 Assistent habe ich folgendes gelesen und deswegen im RF_Core die QueuedConnections angewendet:
Each QThread can have its own event loop. You can start the event loop by calling exec(); you can stop it by calling exit() or quit(). Having an event loop in a thread makes it possible to connect signals from other threads to slots in this threads, using a mechanism called queued connections. It also makes it possible to use classes that require the event loop, such as QTimer and QTcpSocket, in the thread.
Ich wollte nun wissen, ob die task1, "2, "3 und internaltask() auch wirklich vom RF_Thread "bearbeitet" werden, habe in task1, 2, 3 und internalTask() jeweils nen Breakpoint gesetzt und dann (Wir nutzen die Eclipse Europa Umgebung + CDT + Qt Plugin) den gdb Debugger angeworfen.
Dieser zeigt Thread[1] und Thread[2] an. Soweit so gut. Thread1 sollte wohl der Mainthread sein und Thread2 der RF_Thread.
1.
Nun kommt der erste Breakpoint in task1. gdb schreibt
Thread[1](Suspended: Breakpoint hit.)
Thread[2](Suspended)
--> Das ist ja für mich noch plausibel, da der slot direkt über das Objekt aufgerufen wird.
2.
Nun kommt der nächste Breakpoint in task2. gdb schreibt
Thread[1](Suspended: Breakpoint hit.)
Thread[2](Suspended)
--> Das versteh ich nun nicht. Ich habe doch eine QueuedConnection gemacht.
3.
Nun kommt der nächste Breakpoint in task3. gdb schreibt
Thread[1](Suspended: Breakpoint hit.)
Thread[2](Suspended)
--> Auch hier hätte ich gedacht, das Thread2 den Haltepunkt trifft. Es wird ja ein Signal des RF_Cores auf ein Signal des RF_THread verbunden. Und intern im RF_Thread dieses Signal auf den slot task3()
(Halt mal zum Testen, wie es reagiert)
4.
Nach weiteren Haltepunkten kommt dann auch der Haltepunkt in
internalTask(). Was mit dem RF_Core ja nix zu tun hat.
gdb:
Thread[1](Suspended: Breakpoint hit.)
Thread[2](Suspended)
--> Hier hätte ich es mindestens erwartet, das Thread2 reagiert.
Nun gut, jetzt weis ich auch nicht, ob es was mit dem gdb zu tun hat oder so und habe mir folgendes überlegt, um es anders zu testen:
Wenn ich im Task3 des RF_Threads eine while(1) einbaue (Momentan im Code auskommentiert), bin ich von ausgegangen, das RF_Core durch seinen QTimer immer wieder den timerslot() anstößt und der Thread task1 und task2 ausführt und in task3 durch die Endlosschleife ausgelastet ist, aber dann noch mindestens die qDebug's des RF_Core's weiterhin kommen würden, da dieser ja im Mainthread läuft?! Leider kommt kein qDebug mehr
Vielen Dank schonmal im Vorraus für eure Hilfe. Was mach ich falsch, oder geh es falsch an
Viele Grüße