QObject: Cannot create children for a parent that is in a di

Alles rund um die Programmierung mit Qt
Antworten
DBGTMaster
Beiträge: 190
Registriert: 19. August 2010 10:00

QObject: Cannot create children for a parent that is in a di

Beitrag von DBGTMaster »

Hallo,

hätte eine Frage zu QThread, und zwar will ich für jede eingehende TCP Verbindung eigenen Thread starten, funktioniert auch soweit, bis auf folgende Fehlermeldung:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTcpSocket(0x3b4504), parent's thread is QThread(0x3b13d8), current thread is QThread(0x3b44f8)
Nur habe habe im Thread nirgendswo einen parent angegeben??

Code: Alles auswählen

#ifndef TCPSOCKETTHREAD_H
#define TCPSOCKETTHREAD_H

#include <QObject>
#include <QThread>
#include <QTcpSocket>

class TcpSocketThread : public QThread
{
private:
    int m_descriptor;       // Native Verbindug des Sockets
    QTcpSocket m_socket;    // QTcpSocket;

public:
    TcpSocketThread(int descriptor, QObject *parent = 0);

    // Die Threadausführung
    void run();
};

#endif // TCPSOCKETTHREAD_H

Code: Alles auswählen

#include "TcpSocketThread.h"

TcpSocketThread::TcpSocketThread(int descriptor, QObject *parent) : QThread(parent)
{
    // Native Socket- Verbindung
    m_descriptor = descriptor;
}

void TcpSocketThread::run() {

    // TcpSocket erstellen:
    if ( ! m_socket.setSocketDescriptor(m_descriptor) ) {
        qDebug() << __LINE__ << __FILE__ << "Fehlerbehandlung";
    }
    qDebug("waitForReadyRead");
    while (m_socket.waitForReadyRead()) {
        qDebug() << "Data to read...";
    }
}
Mache ich aus m_socket einen Zeiger, so erscheint dieser Fehler nicht mehr...

Aber ich habe doch nirgendswo QTcpSocket einen parent angegeben??

danke!
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Re: QObject: Cannot create children for a parent that is in

Beitrag von solarix »

Vermutlich erstellt QTcpSocket bei "setSocketDescriptor" (also in der run-Methode und daher auch im Thread) ein Child.. das geht eben nicht weil der Socket ja ausserhalb erstellt wurde. Entweder also (wie du selbst gesehen hast) dynamisch (dann wird der QTcpSocket im Thread erstellt) oder du verschiebst den Socket im CTor:

Code: Alles auswählen

TcpSocketThread::TcpSocketThread(int descriptor, QObject *parent) : QThread(parent)
{
   ..
    m_socket.moveToThread(this);
}
Das würde ich sowieso empfehlen (wegen den Signals). Ausserdem würde das auch zusammen mit einem QTcpServer (nextPendingConnection) funktionieren:

Code: Alles auswählen

TcpSocketThread::TcpSocketThread(QTcpSocket *socket, QObject *parent) : QThread(parent)
{
   ..
    m_socket = socket.
    m_socket->setParent(NULL);      // der QTcpServer als Parent entfernen
    m_socket->moveToThread(this); 
}

hth..
DBGTMaster
Beiträge: 190
Registriert: 19. August 2010 10:00

Re: QObject: Cannot create children for a parent that is in

Beitrag von DBGTMaster »

Hallo,

wäre das so korrekt?

Code: Alles auswählen

void TcpSocketThread::run() {

    m_socket.setParent(NULL);
    m_socket.moveToThread(this);
...
}
Frage kann ich mir eigentlich selbst beantworten :=)...
QObject::moveToThread: Current thread (0x7e44f8) is not the object's thread (0x7e13d8).
Cannot move to target thread (0x7e44f8)

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTcpSocket(0x7e4504), parent's thread is QThread(0x7e13d8), current thread is QThread(0x7e44f8)
waitForReadyRead
// Edit:
Also müsste ich an der Stelle moven, wo der Thread erstellt wurde:

Code: Alles auswählen

void TcpServer::incomingConnection(int handle) {

    // Neuen Thread erstellen...
    TcpSocketThread *thread = new TcpSocketThread(handle);
...
}
Nur wie soll ich vom Hauptthread aus auf eine private Eigenschaft des Threads zugreifen???!
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Re: QObject: Cannot create children for a parent that is in

Beitrag von franzf »

Kleine Frage am Rande:
Du weißt dass QTcpSocket bereits asynchron läuft, ein zusätzlicher Thread eigentlich total unnötig ist?
Anstelle des waitForReadyRead() in der run kannst du genauso gut im Hauptthread eine Signal/Slot-Verbindung einrichten. Da blockiert auch nichts.
DBGTMaster
Beiträge: 190
Registriert: 19. August 2010 10:00

Re: QObject: Cannot create children for a parent that is in

Beitrag von DBGTMaster »

Und was ist mit Anfragen, bei welche der Server etwas länger braucht, um das Ergebnis zu liefern?? Dann werden doch alle anderen Anfragen blockiert oder seh ich da was falsch??

lG
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Re: QObject: Cannot create children for a parent that is in

Beitrag von upsala »

Da wird nichts blockiert, was dir auch ein kleines Testprogramm sofort zeigen würde.
DBGTMaster
Beiträge: 190
Registriert: 19. August 2010 10:00

Re: QObject: Cannot create children for a parent that is in

Beitrag von DBGTMaster »

Hallo,

ich glaub, wir reden etwas vorbei :)... Ich erzähl mal:

Client A baut Verbindung zum Server auf.
Client B & Client C bauen ebenso eine Verbindung auf.

- Mit der asynchronen Verbindung ja auch kein Problem.

Client A fordert vom Server nun Daten, sagen wir, der Server braucht 10 Sekunden, um die Daten aufzubereiten (warum er auch immer nur so lange braucht).
Client B will zur gleichen Zeit auch Daten vom Server anfordern, Client B muss aber nun warten, bis die Anfrage der Daten von Client A abgearbeitet wurde, da der MainThread ja nun beschäftigt ist... Sobald der Server die Daten aufbereitet hat, arbeitet er dann natürlich dann sofort die Daten von Client B ab...

Oder lieg ich da wirklich so falsch??
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Re: QObject: Cannot create children for a parent that is in

Beitrag von franzf »

DBGTMaster hat geschrieben:Oder lieg ich da wirklich so falsch??
Ja. Es ist ganz normal, dass ein Server beschäftigt ist. Wäre doch furchtbares Design, wenn bei einer eh schon asynchronen Abarbeitung dieser eine Fall plötzlich alles blockiert, oder?
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: QObject: Cannot create children for a parent that is in

Beitrag von Christian81 »

Ich glaube franzf hat hier Unrecht. Wir haben auch Fälle in denen z.B. an den Server einen Anfrage gestellt wird die etwas länger dauert (SQL-Abfrage, diese zusammenfassen und noch etwas Rechnerei, packen und zurück an den Client als Beispiel). Das haben wir (wie in der Qt Doku bzw. einem Beispiel dort) so aufgezogen dass es für jede Client-Connection einen eigenen Workerthread gibt.
--> http://doc.trolltech.com/4.7/network-th ... erver.html
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Re: QObject: Cannot create children for a parent that is in

Beitrag von solarix »

Tschuldigung dass ich aufgehalten wurde.. unser Nationalfeiertag..

franzf hat ausnahmsweise unrecht... während der Server eine Anfrage von Client A bearbeitet kann ein Client B schon zum Server connecten (weil der QTcpServer bereits threaded ist), aber auch nicht mehr. Denn wie soll eine "nextPendingConnection()" bearbeitet werden, wenn der MainThread mit was anderem beschäftigt ist...?
Nur wie soll ich vom Hauptthread aus auf eine private Eigenschaft des Threads zugreifen???!
Erstens: ganz normal (mit einer Get-Methode). Zweitens das brauchst du doch gar nicht. Dass du "moveToThread()" im Parent-Thread aufgerufen werden muss, bedeutet nicht, dass auch die Methode zu dieser Klasse gehören muss. Ich weiss auch nicht so recht, wie "setSocketDescriptor()" und "moveToThread()" zusammenspielen.. ich verwende daher immer "nextPendingConnection()"

Code: Alles auswählen

void TcpServer::incomingConnection()  // durch Signal "QTcpServer::newConnection()"
{
    while (m_server->hasPendingConnections()) {
      TcpSocketThread *thread = new TcpSocketThread(m_server->nextPendingConnection());
      thread->start();
   }
}

TcpSocketThread::TcpSocketThread(QTcpSocket *socket) 
  : QThread()
{ 
    // hier befinden wir uns ja noch im Mainthread!!! Daher: moveToThread ist erlaubt!
    m_socket = socket;
    m_socket->setParent(NULL);
    m_socket->moveToThread(this);
}

void TcpSocketThread::run()
{
    // erst HIER befinden wir uns in einem anderen Thread-Kontext...!! Hier ist es zu spät!
   ..
}

hth!
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Re: QObject: Cannot create children for a parent that is in

Beitrag von franzf »

ARGH! Genauer lesen das nächste mal ich werd...
Ich dachte dir geht es um die Clients! Dabei steht schon im eröffnenden Post "eingehende Verbindung"...
Kommt davon, wenn man den Post erst spät mitliest, und schon öfter solche Missverständnisse mitbekommen hat.
Naja, Sorry für den Trouble :D
DBGTMaster
Beiträge: 190
Registriert: 19. August 2010 10:00

Re: QObject: Cannot create children for a parent that is in

Beitrag von DBGTMaster »

Gut zu wissen, dass ich nicht totalen blödsinn daher geredet habe :) ...

... Und das ich das moveToThread im Konstrukor durchführen hätte könne, da hätte ich auch selbst draufkommen können :o
Antworten