[gelöst] freigeben dynamisch angelegter QTcpSockets

Alles rund um die Programmierung mit Qt
Antworten
Willi2793
Beiträge: 147
Registriert: 29. September 2008 10:59
Kontaktdaten:

[gelöst] freigeben dynamisch angelegter QTcpSockets

Beitrag von Willi2793 »

Hallo,

ich habe eine kleines Client/Server-Anwendung. Der Server ist auch soweit problemlos. Aber der Client baut Speicher auf. Es ist alles noch im Anfangsstadium des Projektes und die Kommunikation läuft immer gleich ab. Zu Testzwecken mit qDebug() habe ich eine kleine Testklasse angelegt:

TcpSocket.h

Code: Alles auswählen

#ifndef TCPSOCKET_H
#define TCPSOCKET_H

#include <QTcpSocket>

class TcpSocket : public QTcpSocket
{
    Q_OBJECT
public:
    explicit TcpSocket(const QString& n, QObject *parent = 0);
    virtual ~TcpSocket();

private:
    QString name;
};

#endif // TCPSOCKET_H
TcpSocket.cpp

Code: Alles auswählen

#include <QDebug>
#include "tcpsocket.h"

TcpSocket::TcpSocket(const QString& n, QObject *parent) :
    QTcpSocket(parent),
    name(n) {
}

TcpSocket::~TcpSocket() {
    qDebug() << "Destructor: " << name;
}
Also wirklich nur eine Kleinigkeit um im Destruktor eine Ausgabe machen zu können.

Nun habe ich eine Klasse die per moveToThread() einen eigenen Thread bekommt und die einen Slot hat der per Connect an das started()-Signal eines eigenen QThreads gekoppelt wird. Dort wird TcpSocket folgendermassen angelegt:

Code: Alles auswählen

void ConnectionTest::startWork() {
    socket = new TcpSocket(name,this);
    connect(socket, SIGNAL(connected()), this, SLOT(connected()));
    socket->connectToHost("localhost",36001,QIODevice::ReadWrite);
}
"name" wird dem Konstruktor übergeben und ist einfach nur der String "TEST" mit angehängter Nummerierung zum Erkennen. Dann werden ein paar Daten hin und her geschickt. Der Client liest als letztes in folgendem Slot der an readyRead() connected ist:

Code: Alles auswählen

void ConnectionTest::readSocket1009() {
    disconnect(socket, SIGNAL(readyRead()), this, SLOT(readSocket1009()));
    QByteArray txt(socket->readAll());
    connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
    socket->disconnectFromHost();
}
Hier wird also der Socket disconnected(). Der Slot sieht dann so aus:

Code: Alles auswählen

void ConnectionTest::disconnected() {
    qDebug() << "Es soll gelöscht werden: " << name;
    socket->deleteLater();
    socket = NULL;
    emit ended();
}
Das ended()-Signal teilt dann der Verwaltung mit das dieser Thread beendet ist und der dazugehörige QThread beendet werden kann. Das funktioniert auch alels. Aber das

Code: Alles auswählen

socket->deleteLater();
funktioniert nicht immer. Es erscheint folgende Ausgabe in der Console:
Es soll gelöscht werden: "Test00000000001"
Es soll gelöscht werden: "Test00000000002"
Es soll gelöscht werden: "Test00000000003"
Destructor: "Test00000000003"
Es soll gelöscht werden: "Test00000000004"
Destructor: "Test00000000004"
Es soll gelöscht werden: "Test00000000005"
Destructor: "Test00000000005"
Es soll gelöscht werden: "Test00000000006"
Destructor: "Test00000000006"
Es soll gelöscht werden: "Test00000000007"
Destructor: "Test00000000007"
Es soll gelöscht werden: "Test00000000008"
Destructor: "Test00000000008"
Es soll gelöscht werden: "Test00000000009"
Destructor: "Test00000000009"
Es soll gelöscht werden: "Test00000000010"
Destructor: "Test00000000010"
Es soll gelöscht werden: "Test00000000011"
Destructor: "Test00000000011"
Es soll gelöscht werden: "Test00000000012"
Destructor: "Test00000000012"
Es soll gelöscht werden: "Test00000000013"
Destructor: "Test00000000013"
Es soll gelöscht werden: "Test00000000014"
Destructor: "Test00000000014"
Es soll gelöscht werden: "Test00000000015"
Es soll gelöscht werden: "Test00000000016"
Destructor: "Test00000000016"
Woran kann das liegen?

Vielen Dank und Grüße,
Willi
Zuletzt geändert von Willi2793 am 7. April 2011 17:36, insgesamt 1-mal geändert.
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

Ohne ein vollständiges Beispiel schwierig zu sagen. Ich hatte allerdings mal ein ähnliches (oder das gleiche.. das sieht man so nicht) Problem. Das lag daran, dass für das Löschen der Thread ja noch laufen muss, weil das "deleteLater()" ein Auftrag für den Eventloop des Threads ist. Also: kein Thread -> kein Löschen.

Falls du also schön pro Socket ein Thread hast, würde ich einfach die Signals koppeln:

Code: Alles auswählen

connect(socket, SIGNAL(destroyed(QObject *)), 
             thread, SLOT(quit()));

...
irgendwann später:
socket->deleteLater();
Wenn du das "Threading-without-Headache"-Pattern (http://labs.qt.nokia.com/2006/12/04/thr ... -headache/) anwendest, kannst du sogar noch das "finished()"-Signal des Threads mit dem "deleteLater()"-Slot des Threads connecten.. dann bewirkt ein "socket->deleteLater()", dass zuerst der Socket gelöscht wird, dann der Thread beeendet und danach sogar noch der Thread gelöscht wird ;)

hth..
Willi2793
Beiträge: 147
Registriert: 29. September 2008 10:59
Kontaktdaten:

Beitrag von Willi2793 »

solarix hat geschrieben:Ohne ein vollständiges Beispiel schwierig zu sagen. Ich hatte allerdings mal ein ähnliches (oder das gleiche.. das sieht man so nicht) Problem. Das lag daran, dass für das Löschen der Thread ja noch laufen muss, weil das "deleteLater()" ein Auftrag für den Eventloop des Threads ist. Also: kein Thread -> kein Löschen.

Falls du also schön pro Socket ein Thread hast, würde ich einfach die Signals koppeln:

Code: Alles auswählen

connect(socket, SIGNAL(destroyed(QObject *)), 
             thread, SLOT(quit()));

...
irgendwann später:
socket->deleteLater();
Danke, das war der entscheidende Hinweis :)
solarix hat geschrieben:Wenn du das "Threading-without-Headache"-Pattern (http://labs.qt.nokia.com/2006/12/04/thr ... -headache/) anwendest, kannst du sogar noch das "finished()"-Signal des Threads mit dem "deleteLater()"-Slot des Threads connecten.. dann bewirkt ein "socket->deleteLater()", dass zuerst der Socket gelöscht wird, dann der Thread beeendet und danach sogar noch der Thread gelöscht wird ;)

hth..
Ich habe mich nach dem hier gerichtet: http://labs.qt.nokia.com/2010/06/17/you ... -it-wrong/. Aber das ist dasselbe Prinzip :).

Vielen Dank also nochmal!
Antworten