PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Threads erzeugen



LeoManiac
14-04-2004, 19:53
Hi,


ich versuche aus einer Funktion heraus einen Thread zu erzeugen der mir im Sekundentakt einen Socket auf ankommende Daten überprüft aber ich krieg beim Compilieren die folgende Fehlermeldung:


daemon2.cpp: In function `int handling()':
daemon2.cpp:201: ANSI C++ forbids implicit conversion from `void *' in argument passing


Funktion und Aufruf sieht so aus:


void recData(void *name) {
fd_set fdSet;
int rc,read;
char temp[20];
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
FD_ZERO(&fdSet); // Inhalt leeren
FD_SET(c1,&fdSet);
while(1) {
read=select(c1 + 1,&fdSet,NULL,NULL,&tv);
if(read) {
rc = recv(c1, rctext, sizeof(rctext) - 1, 0);
if (rc < 0)
{
writeLog("Error: Cannot recv Data");
pthread_exit((void *) 0);
}
if (rc == 0)
{
writeLog("Other Host has closed the connection !");
pthread_exit((void *) 0);
}
rctext[rc] = '\0';
sprintf(temp,"%i Bytes received: ",rc);
writeLog(((string)temp) + ((string)rctext));
}
}
}

int handling()
{
pthread_t rec,send;
if(pthread_create(&rec, NULL, (void *)&recData, (void *)"Empfangen") != 0) {
writeLog("Fehler beim erzeugen vom Thread rec...");
beenden(200);
} else writeLog("Thread zum empfangen erzeugt...");
pthread_join(rec, NULL);
return false;
}

Diese Methode Threads zu erzeugen hab ich aus den Tutorial von http://pronix.de/modules/C/linux/Linuxsystemprogrammieren_C_Kurs_Kapitel8.php#8_2

Weiß jemand eine Lösung dafür ?

ps: dies ist mein 1. Versuch mit Threads zu arbeiten

[edit] Zeile 201 ist diese :


if(pthread_create(&rec, NULL, (void *)&recData, (void *)"Empfangen") != 0) {

panzi
14-04-2004, 21:20
void recData(void *name); geht nicht.
Da pthread_create() eine Funktion vom Typ void* (*)( void* ) will müsstest du folgendes haben: void * recData(void *name);
Am Ende der Funktion einfach return NULL;
Wobei vor dem return besser ein pthread_exit( NULL ); steht, hab ich gelesen (um wirklich korrekt den thread zu beenden. genau das selbe gilt für den main() thread).

Und warum verwendest du (void *) 0? Das ist das selbe wie NULL, denn so ist es definiert: #define NULL (void*)0

Und warum überprüfst du sekündlich mit select()? Wenns't eh nen thread hast kann der doch ruhig blockieren, oder was ist der Gedanke dahinter?


Im Anhang hab ich nen kleinen server und nen kleinen client, den ich grad' programmiert hab um mich mal mit netzwerkprogrammierung zu beschäftigen.
Ist EXTREM dirty! Überprüf sogar manchmal net ob malloc() funktioniert hatt und ich breche an einigen Stellen bei Fehler einfach ab ohne close() usw.
Ach ja, hab auch keine Kommentare drinn.
Vieleicht findest es trotzdem interessant.

Es is einfach nur ein gethredeter server der von mehreren clients daten empfängt und die synchronisiert auf stdout ausgibt.

LeoManiac
14-04-2004, 21:31
ich überprüfe sekundlich weil ich aus nen anderen Thread heraus auf den selben Socket auch zu jederzeit was senden möchte und wenn der recieve den Socket blockiert geht das schlecht

wie gesagt da es mein erster Versuch mit Threads ist hab ich mich fast vollständig an das Tutorial gehalten.

ich werd mir aber mal dein Code anschauen vieleicht kann ich ja noch was draus lernen ;)

LeoManiac
14-04-2004, 21:56
ich hab die Änderungen gemacht hab aber nach wie vor das gleiche Problem

da ich den g++ Compiler Benutze weil ich C mit C++ gemischt habe im Quelltext kann es sein das es daran liegt aber wie ich das ganze in C++ umsetze weis ich nicht hab dazu noch nichts zu gefunden

panzi
15-04-2004, 14:56
Also die Signatur deiner Funktion ist nun void* (*)( void* )?
Dann nimm bitte das (void*) in der fehlerhaften Zeile weg. Wozu steht das da überhaupt? es wird ja void* (*)( void* ) erwartet, und nicht void*! UNd überhaupt geht jeder Pointer NACH void* eh problemlos ohne cast.

LeoManiac
15-04-2004, 15:34
Ich komm mit den Pointern irgendwie noch nicht so richtig zurecht die Funktion hab ich verstanden ich komm aber bei der Anwendung von Pointern immer noch durcheinander.

[edit] Ich hatte den Parameter Name rausgenommen und hatte dadurch nachdem ich die cast's rausgenommen hatte ständig nen Fehler als den Parameter wieder reingenommen hatte und den Thread mit
pthread_create(&recv, NULL, &recvData,(void *)NULL) erzeugt hatte lief die compilierung problemlos durch.

Deshalb meine Frage braucht eine Funktion für einen Thread immer min. einen Parameter ?

ps: sry wenn ich damit nerven sollte aber so richtig hab ich das eh noch nicht verstanden was zb. void * (*)() bedeutet usw. Pointer ansich sind mir schon klar aber diese Pointer auf void usw. noch nicht so richtig
Wie gesagt ich hab mich beim thread erzeugen an das Tutorial gehalten und da stands so drinn.

panzi
15-04-2004, 21:50
Eins noch vornweg: das (void*) bei (void*)NULL ist auch unnötige, da NULL nur einMakro für ((void*)0) ist. Also bei dir sthet dann: (void*)((void*)0)

@void-Pointer:
Das sind eigentlich einfach nur Pointer auf eine gewisse Speicheraddresse, von der man den Typ der dort abgelegten Variable nciht weiß. Ist quasi einfach eine nackte Speicheradresse.

Und ja, die Thread-Funktion muss immer genau einen Parameter (vom Typ void*) haben. Die Funktionssignatur der Thread-Funktion ist der Typ des 3. Parameters von pthread_create() und man kann nciht etwas von einen falschen Typ übergeben (--> deine Fehlermeldung).

@void* (*)( void* )
Das ist die Signatur eines Funktionspointers auf eine Funktion die void* als Prameter erwartet und auch als Rückgabewert hat:
void* -- der Returnwert vom Typ void*
(*) -- ein Pointer
( void* ) -- Parameterliste: erster und einziger Parameter hat den Typ void*

Natürlich bringt sich so ne Signatur wenig ohne zuweisung zu nen Namen. Also als Parameter braucht so ein Funktionspointer natürlich einen Namen:

int pthread_create( /*...*/ , void* (*funct)( void* ), /*...*/ );

(Genauso hat ja auch der eine Parameter deiner Funktion einen Namen, aber hier kann man den weglassen.)

Man könnte auch void* funct( void*) schreiben, aber das finde ich unschön. (Und ich finde das ist mehr oder weniger ein Fehlerverzeichen der C-Compiler.)

Um nicht jedesmal diese Signatur schreiben zu müssen, wenn man einen Funktionspointer braucht, der auf eine Funktion mit einer solchen Signatur zeigt, kann man auch ein typedef verwenden. Vor allem bei komplexeren Signaturen wird das sinnvoll:

typedef void* (*thread_funct_t)( void* );
Dann kann man einen Funktionspointer (auch wenn man dann das * nicht mehr schreibt, wurde schon im typedef erledigt) wie folgt anlegen:

thread_funct_t funct;
(Zuweisung/Aufruf ist wie gehabt.)

LeoManiac
16-04-2004, 04:10
Was ich dabei aber sehr merkwürdig finde ist das ich nach dem starten des Programms sobald der Client connected 3 Threads habe obwohl ich nur einen erzeuge der 3. wird auch ohne probs wieder beendet der 2. bleibt. Bei jeden weiteren Connect startet der 3. wieder und beendet sich auch wieder mit dem disconnect. Soweit also alles ok aber wieso hab ich 3 Prozesse müsten doch eigentlich nur 2 sein: das Programm selbst und der Thread oder irre ich mich ?



PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
1 7767 7767 7767 ? -1 S 0 0:00 ./daemon2
7767 7769 7767 7767 ? -1 S 0 0:00 ./daemon2
7769 7812 7767 7767 ? -1 S 0 0:00 ./daemon2


ps: das Prog hat die PPID 1 weil ich am anfang der main mit fork einen child prozess starte um aus den Prozess einen Daemon zu machen

Shack
16-04-2004, 23:41
Hi,

zu der Anzahl der Prozesse kann ich dir nicht helfen.

Aber was mich intressiert ist:
Wieso braucht du, oder nimmst du, mehrere Threads und
vor allem, wieso muss man ein Childprozess starten, um aus dem Prozess
ein Dämon zu machen???? Man könnte den Eindruck gewinnen, es existieren hier Verständnisprobleme von deiner Seite aus. Deshalb schreib mal was Du machen
willst. Vielleicht ist dein Ansatz ein völlig falscher. Ich kann mich natürlich auch irren.

cu

LeoManiac
17-04-2004, 05:22
Ich mach das eigentlich nur zum rumprobieren und üben.

Den Thread erzeuge ich weil der ständig am Socket lauschen soll. Zudem soll zu jederzeit was gesendet werden. Ich hab das ganze jetzt auch nicht mehr über select sondern mit fcntl gelöst. Aber ist ja auch irgendwo auch egal , denn wie gesagt ist zum üben ;)

Und das mit den Daemon hab ich von http://pronix.de/modules/C/linux/Linuxsystemprogrammieren_C_Kurs_Kapitel3a.php#3_3, klär könnte man nen Daemon auch anders erzeugen aber so wie es da beschrieben funktionierts Problemlos. Wie gesagt ich hab ANfangs nur einen Prozess erst sobald der Client connected und der Thread zum Empfangen gestartet wird habe ich mehrere Prozesse/Threads in der Prozesslist, wovon 1 Thread auch wieder beendet wird beim Disconect des Clients.

panzi
17-04-2004, 11:44
Hmm, anscheinend kennst du dich besser aus als ich (kein Wunder, hab erst vor kurzem mit sockets angefenagen). Vieleicht kannst du mir beantworten, ob man in zwei threads gleichzeitig von ein und dem selben socket lesen und schreiben kann ohne das sich das stört? Bzw. vieleicht kennst du ne Page wo ich das nachlesen kann. :)
Dazu hab ich auch ne Frage hier (http://www.coding-board.de/board/showthread.php?t=9845) gepostet, vieleicht hätt ich das besser in diesem Forum gepostet... ;)

LeoManiac
17-04-2004, 18:51
Kommt drauf es gibt verschiedene Möglichkeiten entweder benutzt fnctl um den Socket auf Non-Blocking zu setzen. Aber bei der Methode must du ständig abfragen ob Daten zum empfangen sind, da recv nicht mehr blockiert und nicht mehr solange wartet bis Daten angekommen sind.

Oder fragst mit select den Status ab ob der Socket zum Senden frei ist oder ob Daten zum empfangen bereitstehen.


Diese Manpages dürften dir weiterhelfen:
man fcntl
man select
man poll

panzi
17-04-2004, 23:24
thx, werd ich mir dorchlesen (die manpages).