Seite 1 von 2

Sporadischer "Segmentation Fault"

Verfasst: 11. Juni 2008 15:35
von Viper2000
Hallo Forum,

hier mal ein Codeschnipsel:

Code: Alles auswählen

RF_Network_Server_ClientThread::RF_Network_Server_ClientThread(int socketDescriptor, QObject *parent)
	: QThread(parent), socketDescriptor(socketDescriptor)
{
	connect(&mTcpSocket, SIGNAL(readyRead()),
			this, SLOT(readData()));
	connect(&mTcpSocket, SIGNAL(disconnected()),
			this, SLOT(disconnectClient()));
	connect(this, SIGNAL(finished()),
			this, SLOT(deleteLater()));
	
	if (!mTcpSocket.setSocketDescriptor(socketDescriptor))
	{
		///emit error(mTcpSocket.error()); //TODO
		return;
	}
	
	mBlockSize = 0; //BlockSize for received Data
	
	mPeerAddress = getPeerAddress();
	
	qDebug() << "Client Address: " << mPeerAddress;	
	qDebug("***RF_Network_Server: ClientThread constructed***");
}
Wenn ich diesen Konstruktor, der von QThread abgeleitet ist, aufrufe dann bekomme ich ganz unregelmäßig einen "Segmentation Fault". Meistens funktioniert es jedoch einwandfrei!

Die Funktionsweise ist Folgende:
Von einem QTcpServer bekomme ich bei eingehender Verbindung mittels folgendem Code:

Code: Alles auswählen

void RF_Network_Server_ListenServer::incomingConnection(int socketDescriptor)
{
	emit newConnection(socketDescriptor);
}
den Socketdeskriptor der eingehenden Verbindung in einem Signal emittiert.

Dieses Signal stößt folgenden Slot an in dem der Thread erstellt wird:

Code: Alles auswählen

void Gui::createThread(int socketDescriptor)
{
	thread = new RF_Network_Server_ClientThread(socketDescriptor, this);
	connect(thread, SIGNAL(dataReceived(QDomDocument*)), this, SLOT( test(QDomDocument*)));
	myQList.append(thread);
	thread->start();
	qDebug() << "Peer-Address: " << thread->getPeerAddress();
}
Mir ist es nicht begreiflich wie manchmal ein Segmentation fault auftreten kann und manchmal nicht. Manchmal beim ersten Client der connected, manchmal auch erst beim zehnten, manchmal können 100 Clients connecten und es werden 100 Threads ohne Segmentation fault erstellt...

Ich hoffe jemand kann mir helfen.

Gruß, viper

Verfasst: 11. Juni 2008 15:47
von PeterLustig
Hast du denn mal mit dem Debugger geschaut wo genau der Fault entsteht?

Verfasst: 11. Juni 2008 15:52
von Viper2000
mit dem Debugger habe ich nicht geschaut da der Fehler nicht reproduzierbar ist, jedoch wird der Konstruktor

RF_Network_Server_ClientThread::RF_Network_Server_ClientThread

erreicht, aber läuft nicht bis zum Ende durch. Hab da mal durch zwei Debug Ausgaben am Anfang und Ende getestet.

Aber mal allgemien: Wann entsteht überhaupt ein Segmentation Fault? Wenn der Stack überläuft oder was sind da die Gründe dafür?

Gruß, viper

Verfasst: 11. Juni 2008 16:02
von Christian81
Viper2000 hat geschrieben: Aber mal allgemien: Wann entsteht überhaupt ein Segmentation Fault? Wenn der Stack überläuft oder was sind da die Gründe dafür?
Wenn ein Pointer ins Nirvana zeigt.
Benutze einen Debugger und/oder Valgrind und Du wirst es sehr schnell finden. Kann man beides mitlaufen lassen - geht also auch bei sporadischen Crashes.

/edit: Des weiteren solltest Du dir wirklich die Sache mit den QThreads mal anschauen. Das was Du da machst ist... sinnlos.

Verfasst: 11. Juni 2008 16:03
von keeney
Segmentation fault heisst so viel wie Speicherzugriffsfehler. Irgendwo wird auf einen nicht erlaubten Speicherbereich zugegriffen. Ich wuerd mal im Debugger schaun, ob nicht irgendwo ein delete auf ein Objekt ausgefuehrt wird, auf das du spaeter nochmal zugegreifst, und ob alle Variablen wirklich einen gueltigen Wert haben, auf die du zugreifst.

Verfasst: 11. Juni 2008 16:11
von Viper2000
Christian81 hat geschrieben:
Viper2000 hat geschrieben: /edit: Des weiteren solltest Du dir wirklich die Sache mit den QThreads mal anschauen. Das was Du da machst ist... sinnlos.
Ich verstehe absolut nicht wieso das Sinnlos sein sollte. Habe auch mal meinen Software Professor gefragt. Er sagte es wäre die gängige Methode mehrere Clients in eigenen Threads zu bedienen...Vielleicht kannste mir da noch etwas auf die Sprünge helfen was du genau meinst mit dem "sinnlos".

Gruß, viper

Verfasst: 11. Juni 2008 16:21
von Christian81
Schau Dir die Doku von QThread an, dann schau Dir an wo dein TCPSocket erzeugt wird und wie Du deine Connections gemacht hast.
Danach wirst Du sehen das rein gar nichts im Thread passiert sondern alles im Main-Thread. Das meinte ich mit sinnlos.

Verfasst: 11. Juni 2008 16:32
von Viper2000
Ja aber ich tue doch in jedem Thread einen Socket erstellen dem ich den Socketdeskriptor zuweise der vom QTcpServer zurückkommt.

In jedem dieser Threads läuft dann eine eigene Eventloop, die z.B. auf das "readyRead()" Signal des jeweiligen Signals reagiert und die passenden Slots zum lesen der Daten anstößt.

In der offiziellen Trolltech Qt Doku ist es ja im Threaded Fortune Server absolut genauso gemacht wie ich es in mienem Projekt gemacht habe.

Sorry aber ich bin halt ein Newbie der sich erst so langsam in Qt einfinden muss. Da müsst ihr Verständnis für haben. :)

Verfasst: 11. Juni 2008 16:41
von Christian81
Ich glaube nicht das ein Qt-Beispiel genauso aussieht wie dein Code-Schnipsel.
mTcpSocket wird in dem Thread erstellt, in welchen Du ein 'new RF_Network_Server_ClientThread' machst. Deine Connects werden, da im ctor von RF_Network_Server_ClientThread, auch im Main-Thread erzeugt. Da sie nicht queued sind kommt das Signal von mTcpSocket (welcher im MainThread läuft) zwar an, aber auch im Main-Thread.
Also wo wird was im Thread verarbeitet?

Verfasst: 11. Juni 2008 17:45
von Viper2000
soweit, sogut
also sollte ich lieber den mTcpSocket in der "run()" Methode des Threads erzeugen statt im Konstruktor!? Dann würde auch wirklich im thread gearbeitet werden!?

Und wo die Connects hinpacken?

Un zu guter letzt: Wenn ich den mTcpSocket erst in der "run()" des threads erzeuge dann ist er doch außerhalb der run() Methode nicht gültig um in einem anderen Slot des Threads das lesen und schrieben auf den Socket zu machen...

Danke schonmal soweit für deine Hilfen!

Verfasst: 11. Juni 2008 17:56
von Christian81
Viper2000 hat geschrieben: Und wo die Connects hinpacken?
Doku zu connect lesen. Habe im Grunde schon ein Beispiel gezeigt
Viper2000 hat geschrieben: Un zu guter letzt: Wenn ich den mTcpSocket erst in der "run()" des threads erzeuge dann ist er doch außerhalb der run() Methode nicht gültig um in einem anderen Slot des Threads das lesen und schrieben auf den Socket zu machen...
Wie wäre es mit einem Pointer und ein wenig c++?

Verfasst: 11. Juni 2008 18:07
von Viper2000
ich muss auch dazu sagen, dass die Netzwerkklasse ein in sich abgeschlossenes Projekt sein soll.

Die Forderung ist, dass mein Projektpartner in seinem Teilprojekt von meiner Netzwerkklasse einen SocketDeskriptor erhält. Mittels diesem Deskriptor soll er selbst Kommunikationsthreads erstellen und diese auch wieder löschen. Ich hätte die connects, die mit dem Socket zu tun haben, jetzt dahin gesetzt wo der Thread erzeugt wird. So nach dem Motto:

Code: Alles auswählen

meinThread *thread = new meinThread(socketDescriptor, this);
connect(thread, SIGNAL(readyRead()), thread, SLOT(readData()));
aber das müsste ja dann mein Projektpartner machen. Das ist aber insofern schlecht, da er wirklich nur den Thread erzeugen soll bzw. terminieren soll und nicht noch mit irgendwelche internen Sachen wie connects rumwurschteln soll...
Deswegen kam ich auf die Idee die connects in den Konstruktor zu setzen.

Aber wie ich in diesem Fall vorgehen soll damit auch wirklich alles im Thread passiert weiß ich immer noch nicht so wirklich :(

Verfasst: 11. Juni 2008 18:26
von Christian81
Immer noch nicht die connect-Doku gelesen :(

Wenn Du das nicht machen musst - warum machst Du es dann trotzdem? Irgendwie sollte wohl auch spezifiziert sein wie die Daten übergeben werden - oder geht das seit neuesten einfach so?

Verfasst: 11. Juni 2008 18:45
von Viper2000
Ich habe die connect doku durchaus gerade nochmal durchgelesen im Qt4 Assistant. Ich weiß aber leider nicht worauf du hinaus willst.

Warum ich das trotzdem mache? Was meinst du denn mit "trotzdem machen"?

Es ist folgendermaßen spezifiziert:

Mein Projektpartner instanziert eine Klasse von mir die den QTcpServer enthält. Diese horcht auf eingehende connections und emittiert dann einen Signal das einen socketDeskriptor enthält.

Mit diesem SocketDeskriptor erzeugt mein Partner sich meine andere Klasse, diese ist die "Kommunikationsklasse" die in einem Thread laufen soll. Sie enthält einen SendData slot der ein QDomDocument erwartet. Und die Klasse(der Thread) emittiert ein signal mit einem QDomDocument falls etwas empfangen wird.

Dabei soll mein Partner steuern wann ein soclher Kommunikationsthread zerstört wird. In der Regel bleibt der bis zum Programmende bestehen und tauscht Daten mit den Clients die sich connecten aus.

Hoffe jetzt ist klar wie wir es spezifiziert haben. So muss es dann im Endeffekt laufen. Es läuft ja auch schon und wir können Daten mit den Clients austauschen die Connecten. Allerdings stört mich die Sache echt die du angemerkt hast, dass alles in dem MainThread ausgeführt wird...

Bitte nicht ungeduldig mit mir werden. Glaube wir müssen beide erstmal verstehen was wir wollen :D Bin dir auch echt Dankbar für die Hilfe...

Gruß, viper

Verfasst: 11. Juni 2008 19:30
von Christian81
Worauf ich hinaus will? Doku lesen :)

Ich habs immer noch nicht wirklich kapiert. Du hast Kontrolle über beide Klassen - also kannst Du doch auch die connects aus dem ctor nach :run(9 verlagern, oder?
Also den TCPSocket per new in run() erzeugen, connects machen und fertig. Im dtor natürlich nicht vergessen den TCPSocket wieder zu löschen.