Signal an gelöschtes Objekt ?

Alles rund um die Programmierung mit Qt
Antworten
zerobyte
Beiträge: 18
Registriert: 7. August 2012 11:09

Signal an gelöschtes Objekt ?

Beitrag von zerobyte »

Hallo,

ich sitze gerade vor meinem Code und frage mich, ob das so im Langzeitbetrieb funktionieren kann. Zunächst ein wenig Text um alles zu erklären:
Ich programmiere gerade einen kleinen Server auf dem der User sich einloggen muss.
Als erstes wird ein Serverobjekt generiert, dass ein von QTCPServer abgeleitetes Objekt enthält. ( Dieses Objekt hat auch die QList und QHash die ich später noch erwähne )
Sobald eine neue Verbindung erstellt wurde wird ein neues Objekt ( MyClient ) erstellt, das auch ein QTCPSocket enthält und indessen dann der Socketdescriptor geschrieben wird. Dann wird in ein QList der Pointer auf das MyClient-Objekt geschrieben ( falls der Server von sich aus mal Daten an den Client schicken will ) ( Wenn der User sich dann einloggt, wird der Pointer in ein QHash mit dem entsprechenden Usernamen geschrieben und in QList gelöscht ).
Wenn der Client etwas sendet, übermittelt er zuerst die Anzahl an Bytes ( nextBlockSize ) und sendet dann Daten. Sobald bytesAvailable die Größe von
nextBlockSize erreicht hat, werden die verfügbaren Daten ausgelesen und ein Thread in den Threadpool geworfen, der dann die Auswertung der Daten übernimmt ( wenn er
damit fertig ist und eine Antwort senden will, sendet der Thread im Threadpool ein Signal mit dem zu sendenden QByteArray an das MyClient-Objekt ). Klappt auch alles
wunderbar. Jetzt wird die Verbindung irgendwann wieder getrennt und als Folge daraus muss ich das MyClient-Objekt auch wieder löschen. Das Mache ich, wenn zb. das
Socket das disconnected() Signal sendet, Sendet MyClient ein Signal mit dem Pointer auf sich selber an das Serverobjekt um die Pointer aus QList und QHash zu löschen,
danach wendet er ein deleteLater() auf das MyClient-Objekt an. Das wäre jetzt mal der grobe Ablauf, doch jetzt habe ich ein paar Szenarios bei denen ich unsicher bin:

1. Die Verbindung wird getrennt, aber im Threadpool wird noch ein Befehl von der Verbindung ausgeführt. Der Thread antwortet ja mit einem Signal, aber was passiert
wenn das entsprechende MyClient-Objekt schon gelöscht wurde ? Falls es dadurch zu Problemen kommen könnte, würde ich folgendes machen:
( Da das Server-Objekt, das MyClient-Object und das erzeugen des QRunnable-Objects in einem Thread liegen ) Bevor ich den Thread im Threadpool starte könnte ich eine Variable in MyClient um 1 erhöhen ,wenn der Thread die Antwort gesendet hat, könnte ich sie wieder um 1 erniedrigen und das Object darf nur gelöscht werden, wenn die Variable 0 ist. Falls sie nicht 0 ist starte ich einen Timer auf zb 1 sec und versuche dann eine erneute löschung. Aber ist dies wirklich nötig ?

myclient.h

Code: Alles auswählen

#ifndef MYCLIENT_H
#define 

MYCLIENT_H

#include <QObject>
#include <QTcpSocket>
#include <QDebug>
#include <QThreadPool>
#include <QByteArray>

class MyClient : public QObject
{
    Q_OBJECT
public:
    

explicit MyClient(QObject *parent = 0);
    void SetSocket(int Descriptor);
    void readnextBlockSize();
signals:
    void delete_client(MyClient*);
public slots:
    void 

connected();
    void disconnected();
    void readyRead();
    void send(QByteArray);

private:
    QTcpSocket *socket;
    quint32 nextBlockSize;
};

#endif // MYCLIENT_H
myclient.c

Code: Alles auswählen

#include "myclient.h"
#include "task_receivedata.h"
#include <QThreadPool>

MyClient::MyClient(QObject *parent) :
    QObject(parent)
{
    nextBlockSize = 0;
    connect(this,SIGNAL(delete_client(MyClient*)),parent,SLOT(delete_unidentified_connection(MyClient*)));
}

void MyClient::SetSocket(int Descriptor)
{
    socket = new QTcpSocket(this);
    connect(socket,SIGNAL(connected()),this,SLOT(connected()));
    connect(socket,SIGNAL(disconnected()),this,SLOT(disconnected()));
    connect(socket,SIGNAL(readyRead()),this,SLOT(readyRead()));

    socket->setSocketDescriptor(Descriptor);

    qDebug() << "client connected";
}

void MyClient::connected()
{
    qDebug() << "client connected event";
}

void MyClient::disconnected()
{
    qDebug() << "client disconnected";
    emit delete_client(this);
}

void MyClient::send(QByteArray array)
{
    socket->write(array);
}

void MyClient::readyRead()
{
    if(nextBlockSize == 0 && socket->bytesAvailable() >= 4)
    {
        readnextBlockSize();
        qDebug() << nextBlockSize;
    }
    if(nextBlockSize != 0 && socket->bytesAvailable() >= nextBlockSize)
    {

        qDebug() << "Thread start";
        task_receivedata *receivedata = new task_receivedata(socket->read(nextBlockSize),nextBlockSize);
        receivedata->setAutoDelete(true);
        connect(receivedata,SIGNAL(send_data(QByteArray)),this,SLOT(send(QByteArray)),Qt::QueuedConnection);
        QThreadPool::globalInstance()->start(receivedata);
        nextBlockSize = 0;
        return;
    }
}

void MyClient::readnextBlockSize()
{
    QByteArray blocksize(socket->read(4));
    union
    {
        char Blocksizein[4];
        quint32 BlockSizeout;
    } x;
    char *p = x.Blocksizein;
    *p++ = blocksize[0];
    *p++ = blocksize[1];
    *p++ = blocksize[2];
    *p = blocksize[3];
    nextBlockSize = x.BlockSizeout;
}
Mfg
veeman
Beiträge: 277
Registriert: 3. Oktober 2012 01:43
Kontaktdaten:

Re: Signal an gelöschtes Objekt ?

Beitrag von veeman »

Ich glaub Qt löst beim Zerstören eines Objekts alle Signalreferenzen auf.
Du kannst es aber auch ganz einfach selbst überprüfen, in dem du deinen Clienten freigibst, während ein Thread läuft in welchem du dann per dumpObjectInfo() alle SIGNALE/SLOTS des Thread überprüfst.

Mfg veeman
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Re: Signal an gelöschtes Objekt ?

Beitrag von franzf »

veeman hat geschrieben:Ich glaub Qt löst beim Zerstören eines Objekts alle Signalreferenzen auf.
Wenn man sich nicht sicher ist schaut man in die Doku:
QObject::~QObject () [virtual]
Destroys the object, deleting all its child objects.
All signals to and from the object are automatically disconnected, and any pending posted events for the object are removed from the event queue. However, it is often safer to use deleteLater() rather than deleting a QObject subclass directly.
Antworten