Seite 1 von 2

[gelöst]QThread finished Signal wird nicht ausgelöst

Verfasst: 20. August 2010 09:12
von Alex66955
Hallo Community,

Habe folgendes Problem.
Besitze mehrere Threads(bis zu 50) jeder dieser thread erzeugt ein Objekt einer Klasse und geht dann in den EventLoop um auf ein Signal von dieser Klasse zu warten. Wenn das Signal kommt wird in einem Zeitintervall eine Methode der erstellten Klasse gestartet und wieder auf das Signal gewartet das ist die Grundfunktion der Threads.
Nun zum sicheren beenden. Aus irgendwelchen Gründen Funkioniert das Beenden nicht.
Folgende Vorgehensweise: ich Setze von Auserhalb eine Boolean und im Thread prüfe ich auf den Warheitswert dessen. Trifft der Boolean zu beende ich den EventLoop mit this->quit oder this->exit(0). Nun müsste ja der Thread selbstständig ein finished() Signal emitieren wenn der EventLoop beendet worden ist und kann dann von Auserhalb mit thread->deleteLater reagieren..
Das selstsame ist von beispielsweise 5 Threads senden 3 bis 4 ein finished Signal und der Rest macht nix -.-

Oder habe ich in meinem System einen Denkfehler eingebaut?

Nun ein wenig Code

Thread:

Code: Alles auswählen

void SearchVehicle::run() {

    connectTimeIntervall = 6;
    disconnectTimeIntervall = 4;

    isRequestClose = false;

    connectToFtp = new ConnectFtp();

    initSignalSlot();

    connectToFtp->startConnect();

    exec();
}

void SearchVehicle::initSignalSlot(){
    qRegisterMetaType<QList<QUrlInfo> > ("QList<QUrlInfo>");
    connect(connectToFtp, SIGNAL(readyToAction(QList<QUrlInfo>, QList<QUrlInfo>)), this, SLOT(addVehicleFileInfo(QList<QUrlInfo>)));
}


SearchVehicle::SearchVehicle(){
        this->moveToThread(this);
}


void SearchVehicle::addVehicleFileInfo(QList<QUrlInfo> fileInfoList) {
    //MACHT WAS..
    searchFinish();
}




void SearchVehicle::requestClose(){
    mutex.lock
    isRequestClose = true;
    mutex.unlock
}



void SearchVehicle::startSearch() {

    connectToFtp = new ConnectFtp();

    initSignalSlot();

    connectToFtp->setSettings(ftpSettings);
    connectToFtp->startConnect();

}



void SearchVehicle::searchFinish() {
    mutex.lock
    if(isRequestClose){
    mutex.unlock
        qDebug() << "beendet gesendet " << currentVehicle->getVehicleName();
        this->exit(0);
        return;
    }else{
        emit finish(currentVehicle);
        if(currentVehicle->getConnectStatus()){
            this->sleep(connectTimeIntervall);
            startSearch();
        }else{
            mutex.unlock
            this->sleep(disconnectTimeIntervall);
            startSearch();
        }
        
        
    }
}


Übergeordnete Klasse zum beenden..

Code: Alles auswählen

void VehicleFileList::requestCloseProgress(){
    currentCloseThreadCount = 0;
    isCloseProgress = true;

    for(int i=0; i < threadList.length(); i++){
        connect(threadList[i], SIGNAL(finished()), this, SLOT(threadCloseSlot()));
        threadList[i]->requestClose();
    }
}



void VehicleFileList::threadCloseSlot(){
    mutex.lock();
    currentCloseThreadCount++;
    qDebug() << currentCloseThreadCount;
    mutex.unlock();

    if(threadList.length() > 0){
        qDeleteAll(threadList.begin(), threadList.end());
    }
        emit closeFinish();

        return;
    }
}


Verfasst: 20. August 2010 09:49
von Christian81
Dein Mutex-Locking in searchFinish() ist fehlerhaft. Dafür gibt es QMutexLocker.
Und um das Ganze zu vereinfachen würde ich eine QSemaphore missbrauchen und wenn isAvailable() == 0 -> Thread beenden.

Verfasst: 20. August 2010 10:13
von Alex66955
Christian81 hat geschrieben:Dein Mutex-Locking in searchFinish() ist fehlerhaft. Dafür gibt es QMutexLocker.
Und um das Ganze zu vereinfachen würde ich eine QSemaphore missbrauchen und wenn isAvailable() == 0 -> Thread beenden.
Ist das auch die Uhrsache für das nicht gesendete finished() Signal? Also das der gleichzeitige Zugriff auf den Boolean den Thread daran hindert das blöde Signal zu senden.


Zu QSemaphore:
Da habe ich nicht ganz verstanden was du meinst. Ich gebe ja die zu verfügung stehende Ressourcen an. Das heißt bei isAvailable() == 0 bedeutet keine Ressourcen mehr vorhanden und der soll alle Threads mit deletelater löschen??

EDIT:
QMutexLocker hat keiner Veränderung gebracht.

Verfasst: 20. August 2010 11:47
von Christian81
Semaphore: Jeder Thread hat eine Semaphore mit dem Wert 1. Wenn Du den Thread beenden willst einfach die Semaphore auf 0 setzen. Im Thread prüfst Du einfach auf semaphore != 0 und beendest dich indem Du die Eventloop verlässt.

Signal: Siehst Du die Debugausgabe oder nicht? isRequestClose würde ich auf alle Fälle volatile definieren.

Verfasst: 20. August 2010 12:04
von Alex66955
Christian81 hat geschrieben:Semaphore: Jeder Thread hat eine Semaphore mit dem Wert 1. Wenn Du den Thread beenden willst einfach die Semaphore auf 0 setzen. Im Thread prüfst Du einfach auf semaphore != 0 und beendest dich indem Du die Eventloop verlässt.
Okay verstanden werde dies dann auch so umsetzen. Aber dient auch nur zur übersichtlichkeit und ist eben nur ein andere Weg um den Eventloop zu schließen.

Christian81 hat geschrieben: Signal: Siehst Du die Debugausgabe oder nicht? isRequestClose würde ich auf alle Fälle volatile definieren.
Ja die Debugausgabe sehe ich, nur wird das finished() nicht immer gesendet. Dazu muss ich noch sagen das ich herausgefunden habe das es wohl an der Unterklasse liegt die von dem thread ausgeführt wird. Nehme ich diese heraus und erzeuge manuell ein emit mit dem QTimer funktioniert das ganze. Sprich die aufgerufene Klasse blockiert in irgendeiner art und weise das emitieren des finished() Signal ich habe aber keine ahnung wieso.

Hier die gekürzte unter Klasse

Code: Alles auswählen


#include "connectftp.h"

/**
 * @brief Konstruktor dieser Klase
 *
 * @param parentTemp ElternWidget
 */
ConnectFtp::ConnectFtp(QWidget* parentTemp) {
    ftpConnect = new QFtp();
    initSettings();
    
    connectionTimeOutTimer  = new QTimer();
    loginTimeOutTimer       = new QTimer();
    downloadTimeOutTimer    = new QTimer();
    directoryTimeOutTimer   = new QTimer();

    isStarted = false;

    connectionTimeOutTimer->setSingleShot(true);
    loginTimeOutTimer->setSingleShot(true);
    downloadTimeOutTimer->setSingleShot(true);
    directoryTimeOutTimer->setSingleShot(true);

    fileCounter     = 0;
    parent          = parentTemp;
}


/**
 * @brief Initialisieren der Einstellungen
 */
void ConnectFtp::initSettings() {
    timeOut = wholeSettings.getFtpTimeOut();
}


/**
 * @brief Verbinung initiiren
 *
 * Legt wenn vorhanden ein Proxy fest und verbindet sich mit den angegebenen Anmeldedaten mit dem FTP-Server
 * Bei einem Fehlschlag wird ein Signal an den ftpCommandFinished Slot gesendet.
 */
bool ConnectFtp::initConnection() {
    if(!ping()){
        emit ftpFail(1);
        return false;
    }

    connectionTimeOutTimer->start(timeOut);
    
    if (isFtpProxy) {
        ftpConnect->setProxy(ftpProxy, ftpPort);
    }
    ftpConnect->connectToHost(ftpHost, ftpPort);


    if (ftpUser.isEmpty() && ftpPassword.isEmpty()) {
        ftpConnect->login();
    } else {
        ftpConnect->login(ftpUser, ftpPassword);
    }
    return true;
}




/**
 * @brief Einsprungspunkt der FTP-Aktionen
 *
 */
void ConnectFtp::startConnect() {

    QDir dir;
    if(!dir.exists(tempFileDirectory)){
        dir.mkdir(tempFileDirectory);
    }

    if(!isStarted){
        initSignalSlot();
        initSettings();
        isStarted = true;
        if(!initConnection()) return;
        ftpConnect->list(ftpDirectory);
    }else{
        if(!ping()){
            emit ftpFail(1);
            return;
        }
        ftpConnect->list(ftpDirectory);
    }
}



/**
 * @brief Initialisieren der Signale und Slots
 *
 * @li Verbinden des QFTP-Signal commandFinished mit dem eigenen Slot ftpCommandFinished
 * @li Verbindem des QFTP-Signal listInfo mit dem eigenen Slot ftpList
 * @li Verbinden der Timeout Signale
 *
 * @see ftpCommandFinished(int, bool)
 */
void ConnectFtp::initSignalSlot() {
    connect(ftpConnect, SIGNAL(commandFinished(int, bool)), this, SLOT(ftpCommandFinished(int, bool)));
    connect(ftpConnect, SIGNAL(listInfo(QUrlInfo)), this, SLOT(ftpList(QUrlInfo)));
    connect(connectionTimeOutTimer, SIGNAL(timeout()), this, SLOT(connectionTimeOut()));
    connect(loginTimeOutTimer, SIGNAL(timeout()), this, SLOT(loginTimeOut()));
}



/**
 * @brief Liste mit verfügbaren Dateien auf dem FTP-Server abrufen
 *
 * @param url Dateipfad auf dem FTP-Server
 */
void ConnectFtp::ftpList(QUrlInfo url) {
    if (url.isFile() && url.isValid() && url.isReadable()) {
        fileUrlList.append(url);
    }
    if (url.isDir() && url.isValid() && url.isReadable()){
        directoryUrlList.append(url);
    }
}



/**
 * @brief Dieser Slot wird aufgerufen wenn ein Abgeschlossener Befehl der QFTP Klasse gesendet worden ist
 * 
 * @param commandId QFtp Befehls ID
 * @param isError Qftp ist Befehl fehlgeschlagen?
 *
 * Durch einen Abgeschlossenen Befehl wird ein Signal von QFtp an diese Methode gesendet.
 * 
 * Bei einem Fehler wird von hier ein Signal mit der Fehler ID gesendet
 * SIGNAL: ftpFail(int)
 *
 * @li ID: 1 --> Timeout
 * @li ID: 2 --> LoginDaten ungültig
 * @li ID: 3 --> Verzeichnis ungültig
 * @li ID: 4 --> Fehler beim downloaden
 * @li ID: 5 --> Fehler beim Speichern des Downloads
 * @li ID: 6 --> Fehler beim Upload
 */
void ConnectFtp::ftpCommandFinished(int commandId, bool isError) {
    if (ftpConnect->currentCommand() == QFtp::ConnectToHost) {
        connectionTimeOutTimer->stop();
        if (isError) {
            ftpConnect->abort();
            emit ftpFail(1);
        }else{
            if(isIp){
                 loginTimeOutTimer->start(timeOut);
            }     
        }  
    }
    if (ftpConnect->currentCommand() == QFtp::Login) {
        loginTimeOutTimer->stop();
        if (isError) {
            ftpConnect->abort();
            emit ftpFail(2);
        }else{
            directoryTimeOutTimer->start(timeOut);
        }
    }

        }
    }
    if (ftpConnect->currentCommand() == QFtp::List) {
        directoryTimeOutTimer->stop();
        if (isError) {
            emit ftpFail(3);
        } else {
            connectionTimeOutTimer->stop();
            emit readyToAction(fileUrlList, directoryUrlList);
        }
    }
}


/**
 * @brief ConnectionTimeout Slot
 *
 * Wenn die Zeit des timers abgelaufen ist wird dieser Slot aufgerufen
 */
void ConnectFtp::connectionTimeOut() {
    this->blockSignals(true);
    loginTimeOutTimer->stop();
    ftpConnect->clearPendingCommands();
    ftpConnect->abort();
    this->blockSignals(false);
    emit ftpFail(1);
}


/**
 * @brief ConnectionTimeout Slot
 *
 * @return Boolean ob ping Erfolgreich war
 */
bool ConnectFtp::ping(){
    QProcess ping;
    QString countEcho = "3";
    QString returnTimeout = "50";

    QStringList arguments;
    arguments  << ftpHost << "-n" << countEcho << "-w" << returnTimeout ;
    ping.start("ping ", arguments);

    if(ping.waitForStarted(1000)){
        if(ping.waitForFinished(4000)){
            if(ping.exitCode() == 0){
                return true;
            }else{
                return false;
            }
        }
    }
    return false;
}



/**
 * @brief loginTimeOut Slot
 *
 * Wenn die Zeit des timers abgelaufen ist wird dieser Slot aufgerufen
 */
void ConnectFtp::loginTimeOut() {
    if(ping()){
        ftpConnect->clearPendingCommands();
        ftpConnect->abort();
        emit ftpFail(2);
    }else{
        emit ftpFail(1);
    }
}


/**
 * @brief directoryTimeOut Slot
 *
 * Wenn die Zeit des timers abgelaufen ist wird dieser Slot aufgerufen
 */
void ConnectFtp::directoryTimeOut(){
    emit ftpFail(3);
    if(ping()){
        ftpConnect->clearPendingCommands();
        ftpConnect->abort();
        emit ftpFail(3);
    }else{
        emit ftpFail(1);
    }
}


/**
 * @brief Destruktor
 *
 * Löschen der erzeugten Objekte
 */
ConnectFtp::~ConnectFtp() {
    //ftpConnect->abort();
    //ftpConnect->close();
    ftpConnect->deleteLater();
    connectionTimeOutTimer->deleteLater();
    loginTimeOutTimer->deleteLater();
    downloadTimeOutTimer->deleteLater();
    directoryTimeOutTimer->deleteLater();

}




Verfasst: 20. August 2010 12:16
von Christian81

Code: Alles auswählen

SearchVehicle::SearchVehicle(){
        this->moveToThread(this);
} 
Das ist Blödsinn... aber das steht ja in einem anderen Thread.
Des weiteren wird connectToFtp zweimal instanziiert (einmal in run() und einmal in startSearch()
Wenn startSearch() mehr als einmal aufgerufen wird wird auch mehrmals ein connect() ausgeführt.
Also bring ein minmal kompilierbares Beispiel und wir sehen weiter. So sehe ich nichts was das Beenden der Eventloop verhindern würde.

Verfasst: 20. August 2010 13:21
von Alex66955
Christian81 hat geschrieben: Wenn startSearch() mehr als einmal aufgerufen wird wird auch mehrmals ein connect() ausgeführt.
Das scheint das Problem zu sein wenn ich startSearch() hier herausnehme funktioniert das ganze. Jedoch mit ein paar schwierigkeiten. Wie setze ich das ganze System des Threads in Kraft ohne in der Run Methode den Anstoß mit startSearch() zu geben.
Hier mal mein Konstrukt. Nur ist es problematisch das ganze zu starten da beim aufrufen von thread->start() und danach thread->startSearch es sein kann das die Run Methode noch nicht abgelaufen ist und schon startSearch ausgeführt wird --> Absturz des Programm. Natürlich könnte man mit einem Sleep oder ähnliches nachhelfen ist aber sehr unschön.. Ich glaube ich habe ein Konzept Fehler in meinem System.

Gerüst:

Code: Alles auswählen

void SearchVehicle::run() {
    connectTimeIntervall = 6;
    disconnectTimeIntervall = 4;

    isRequestClose = false;
    isRun = false;

    connectToFtp = new ConnectFtp();
    connectToFtp->setSettings(ftpSettings);
    initSignalSlot();
    exec();
}


void SearchVehicle::initSignalSlot(){
    connect(connectToFtp, SIGNAL(readyToAction()), this, SLOT(searchFinish()));
}


void SearchVehicle::requestClose(){
    mutex.lock
    isRequestClose = true;
    mutex.unlock
}


//WIRD VON ÜBERGEORDNETER KLASSE GESTARTET      
void SearchVehicle::startSearch() {
    QMutexLocker locker(&mutex);
    if(isRequestClose){
        this->exit(0);
        return;
    }else{
        locker.unlock();
        connectToFtp->startConnect();    // WARTET DANACH AUF DAS SIGNAL DER UNTERKLASSE
    }
}


void SearchVehicle::searchFinish() {
    //SENDET SIGNAL ... UND MACHT WAS
    startSearch();
}



SearchVehicle::~SearchVehicle() {
    connectToFtp->deleteLater();
}



Verfasst: 20. August 2010 13:42
von Christian81
Du kannst in run() ja genauso auf eine (andere!) Semaphore mit QSemaphore::acquire() warten. Wenn Du loslegen willst machst Du einfach QSemaphore::release() und schon fängt Dein Thread an zu rennen.

Verfasst: 20. August 2010 14:58
von Alex66955
Christian81 hat geschrieben:Du kannst in run() ja genauso auf eine (andere!) Semaphore mit QSemaphore::acquire() warten. Wenn Du loslegen willst machst Du einfach QSemaphore::release() und schon fängt Dein Thread an zu rennen.
Okay hab das soweit umgesetzt und Funktioniert auch (Mit dem löschen/finsihed()).
Nun kommt aber die Fehlermeldung "QObject::startTimer: timers cannot be started from another thread" jedoch nicht immer. Diese stammt wohl aus meiner Unterklasse. Bevor die Meldung kommt friert meine Gui für einige Sekunde ein.
Daraufhin hab ich connectToFtp = new ConnectFtp() aus der Run-Method rausgenommen und der Fehler kommt nicht mehr. Mhh
Aber das einfrieren meiner Gui für ca. 6 sec bleibt bestehen. Dazu muss ich noch sagen wenn ich "this->moveToThread(this);" aus der startSearchmethode nehme bleibt sie eingefroren. Die Debug ausgabe bei startSearch kommt aber Regelmäßig.
Jetzt verstehe ich nix mehr :(

Aktuelle Implementierung:

Code: Alles auswählen



#include "searchvehicle.h"

void SearchVehicle::run() {
    connectTimeIntervall = 6;
    disconnectTimeIntervall = 4;

    isRequestClose = false;
    isRun = false;

    startSemaphore.release();
    exec();
}

SearchVehicle::SearchVehicle(){  
}

void SearchVehicle::initSignalSlot(){
    connect(connectToFtp, SIGNAL(ftpFail()), this, SLOT(searchFinish());
}


void SearchVehicle::requestClose(){
    mutex.lock
    isRequestClose = true;
    mutex.unlock
}


void SearchVehicle::startSearch() {
    this->moveToThread(this);
    qDebug() << "läuft..";
    startSemaphore.acquire();
    startSemaphore.release();
    QMutexLocker locker(&mutex);
    
    if(!isRun){
        connectToFtp = new ConnectFtp();
        connectToFtp->setSettings(ftpSettings);

        initSignalSlot();
        isRun = true;
    }


    if(isRequestClose){
        this->exit(0);
        return;
    }else{  
        connectToFtp->startConnect();
    }
    locker.unlock();
}


void SearchVehicle::addVehicleFileInfo(QList<QUrlInfo> fileInfoList) {
    // DO SOMETHING
    searchFinish();
}


void SearchVehicle::searchFinish() {
    QMutexLocker locker(&mutex);

    emit finish(currentVehicle);

    if(currentVehicle->getConnectStatus()){
        this->sleep(connectTimeIntervall);
    }else{
        this->sleep(disconnectTimeIntervall);
    }
    locker.unlock();
    startSearch();
}

Code: Alles auswählen

        for (int i = 0; i < threadList.length(); i++) {
            threadList[i]->start();
            threadList[i]->startSearch();
        }
EDIT: Die Semaphoren verursachen also auch eine Art sleep der übergeordneten Klasse.. Also müsste dies auch noch in einem Thread sein um das blockieren zu verhindern? Oder gibts eine einfachere Möglichkeit

Verfasst: 20. August 2010 15:45
von Christian81
Zu deinen Problemen habe ich in deiner vorigen Frage schon genug geschrieben...

/edit: und das mit dem Semaphoren ist ja auch irgendwie... üerflüssig

Verfasst: 20. August 2010 16:21
von Christian81
Ich habe mir das nochmal angeschaut und kapiere rein gar nicht was das alles soll ...

Du startes eine QThread-Eventloop aber wo rufst Du dann startSearch() auf? Die Semaphoren sind, so wie du sie benuzt komplett überflüssig. Das metoThread ebenso (siehe anderer Thead!) Und mutexlocker.unlock() ist auch überflüssig - dazu ist ja ein MutexLocker da dass man daran nicht denken braucht.

Verfasst: 20. August 2010 16:44
von Alex66955
Christian81 hat geschrieben:Ich habe mir das nochmal angeschaut und kapiere rein gar nicht was das alles soll ...
Da gebe ich dir Recht. Hock jetzt seit heute Morgen um 8 Uhr an diese Blöden Stelle un komm einfach nicht weiter, vieleicht sollte ich einfach schluss machen und in den feierabend gehen.
Christian81 hat geschrieben: Und mutexlocker.unlock() ist auch überflüssig - dazu ist ja ein MutexLocker da dass man daran nicht denken braucht.
Jetzt sehe ich es auch Der QMutexLocker lockt alles bis die Methode von der er aufgerufen worden ist geschlossen wird. Also unlock raus und auch den Mutexlocker der Unter-Methode und fertig.
Christian81 hat geschrieben: Du startes eine QThread-Eventloop aber wo rufst Du dann startSearch() auf?
In der Übergeordnete Klasse (siehe letzte Antwort)
Klasse von der aus der Thread gestartet wird:

Code: Alles auswählen

        for (int i = 0; i < threadList.length(); i++) {
            threadList[i]->start();
            threadList[i]->startSearch();
        } 
Christian81 hat geschrieben: Die Semaphoren sind, so wie du sie benuzt komplett überflüssig
Das habe ich mir schon gedacht. Ich versuche nochmal ganz stark meine Birne anzustrengen und mit den Tipps von dir die implementierung mit den Semaphoren hinzubekommen..und der Fehler mit "QObject::startTimer: timers cannot be started from another thread" tritt auch wieder auf :(

Verfasst: 20. August 2010 16:47
von Christian81

Code: Alles auswählen

threadList[i]->startSearch(); 
Das ruft zwar die Funktion auf, aber es läuft immer noch im Hauptthread... wie sollte bei einem einfachen Aufruf ein Threadwechsel passieren?

Ich würde sagen fang von vorn an, erstmal einen einfachen Thread dem Du was üergibst und der im Thread dann damit etwas macht.

Verfasst: 20. August 2010 17:13
von Alex66955
Christian81 hat geschrieben: Ich würde sagen fang von vorn an, erstmal einen einfachen Thread dem Du was üergibst und der im Thread dann damit etwas macht.
Hast Recht. Hat keinen Sinn da weiter zu machen. Danke für die vielen Tipps..Mach mich ab in den Feierabend. Und Am Montag an das Zeichenblatt.

Gruß Alex

Verfasst: 23. August 2010 13:20
von Alex66955
Ich komme immer noch nicht weiter. Hab jetzt ein minimal Beispiel gebastelt in der Hoffnung jemand kann mir meinen Denkfehler offen legen.

Ich Habe eine Klasse nonThread die mir signale sendet und im Thread selbst erzeugt wird. Im Thread wird auf das Signal gewartet bei ankommendes Signal wird eine Methode der nonThread Klasse gestartet die wiederum ein signal sendet wenn sie fertig ist... Das soll so lange gehen bis der Benutzer den isClose boolean setzt.

Mir ist klar das mein Beispiel nicht Thread sicher ist und habe jene Implementierung weggelassen.

Code: Alles auswählen

this->moveToThread(this);
Wenn ich diesen Befehl im Konstruktor weglasse wird die Gui Blockiert. Mir ist aber nur halb klar warum. Ich nehme an das durch das aufrufen der Unterklasse der Kontext im MainThread liegt und deswegen die Gui Blockiert. Also notwendig??

In der Main Klasse wo der Thread erzeugt wird habe ich das finished() Signal mit dem deleteLater() Slot des Threads verbunden das bei einem quit/exit der Thread gelöscht wird.
--> Funktioniert jedoch nicht! Sprich Boolean wird gesetzt aber kein finished() Signal gesendet bzw Destruktor aufgerufen.

Ich komme einfach nicht weiter habe mir allesmögliche durchgelesen und im Internet gesucht. Aber hab momentan eine komplette denkblokade in Bezug auf QThreads..

thread:

Code: Alles auswählen

void Thread::run(){
    isClose=false;
    noneThread = new NonThread();
    connect(noneThread, SIGNAL(senden()), this, SLOT(wiederholen()), Qt::QueuedConnection);
    exec();
}

Thread::Thread(){
    this->moveToThread(this);
}

void Thread::wiederholen(){
    qDebug() << "Wiederholen";
    if(isClose){
        this->quit();
        return;
    }
    this->sleep(2);
    noneThread->sendenbegin();
}

void Thread::requestClose(){
    qDebug() << "request close";
    isClose= true;
}


Thread::~Thread(){
      qDebug() << "thread gelöscht";
      noneThread->deleteLater();
}
main:

Code: Alles auswählen

MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow){
    ui->setupUi(this);

    myThread = new Thread;
    connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(closeThread()));
    connect(myThread, SIGNAL(finished()), myThread, SLOT(deleteLater()), Qt::QueuedConnection);
    myThread->start();

}


void MainWindow::closeThread(){
    myThread->requestClose();
}