Noch kleinere Probleme mit Thread
-
Hallo Leute,
erst mal Danke für eure Hilfe.
Mittlerweile tut mein Programm das was ich will!
Aber jetzt kommt was kurioses oder ich stehe vor einem UTS Problem :)....Hier mal mein noch einfaches Thread-Programm:
#define FOREVER for(;;)
using namespace std;
DWORD WINAPI handle_error(FLAG *error_flag)
{
FOREVER
{
// printf("ErrorFlag in thread :\n");switch ( error_flag->Error_Flag )
{
case WSANOTINITIALISED :
printf("Unable to initialise socket.\n");
break;
case WSAEAFNOSUPPORT :
printf("The specified address family is not supported.\n");
break;
case WSAEADDRNOTAVAIL :
printf("Specified address is not available from the local machine.\n");
break;
case WSAECONNREFUSED :
printf("The attempt to connect was forcefully rejected.\n");
break;
case WSAEDESTADDRREQ :
printf("address destination address is required.\n");
break;
case WSAEFAULT :
printf("The namelen argument is incorrect.\n");
break;
case WSAEINVAL :
printf("The socket is not already bound to an address.\n");
break;
case WSAEISCONN :
printf("The socket is already connected.\n");
break;
case WSAEADDRINUSE :
printf("The specified address is already in use.\n");
break;
case WSAEMFILE :
printf("No more file descriptors are available.\n");
break;
case WSAENOBUFS :
printf("No buffer space available. The socket cannot be created.\n");
break;
case WSAEPROTONOSUPPORT :
printf("The specified protocol is not supported.\n");
break;
case WSAEPROTOTYPE :
printf("The specified protocol is the wrong type for this socket.\n");
break;
case WSAENETUNREACH :
printf("The network can't be reached from this host at this time.\n");
break;
case WSAENOTSOCK :
printf("The descriptor is not a socket.\n");
break;
case WSAETIMEDOUT :
printf("Attempt timed out without establishing a connection.\n");
break;
case WSAESOCKTNOSUPPORT :
printf("Socket type is not supported in this address family.\n");
break;
case WSAENETDOWN :
printf("Network subsystem failure.\n");
break;
case WSAHOST_NOT_FOUND :
printf("Authoritative Answer Host not found.\n");
break;
case WSATRY_AGAIN :
printf("Non-Authoritative Host not found or SERVERFAIL.\n");
break;
case WSANO_RECOVERY :
printf("Non recoverable errors, FORMERR, REFUSED, NOTIMP.\n");
break;
case WSANO_DATA :
printf("Valid name, no data record of requested type.\n");
break;
case WSAEINPROGRESS :
printf("address blocking Windows Sockets operation is in progress.\n");
break;
case WSAEINTR :
printf("The (blocking) call was canceled via WSACancelBlockingCall().\n");
break;
default :
// printf("Unknown error.\n");
break;
}
}
return 1;
/*WSACleanup();*/
/* exit(0); */
}Binde ich den printf Befehl (ganz oben) in das Programm ein, funktioniert der Thread.
Dokumentiere ich den Befehl aus, dann funktioniert der Thread nicht.Wenn mir jemand einen Tipp geben kann warum das so ist. Oder ob der Fehler noch wo anders liegt....
Danke und Grüße
Tentone
-
Dokumentiere ich den Befehl aus, dann funktioniert der Thread nicht.
Heisst? Compiler Error? Linker Error? Runtime Error? EXceptions?
SimonBTW: Benutze die Code- bzw. C/C++ Tags.
-
Was soll übrigens das forever- loop #define?
Das macht dein Code nur unlesbarer, zudem können mit Makros unerwartete Fehler auftreten.Ich würds bleiben lassen...
Simon
-
simon.gysi schrieb:
Dokumentiere ich den Befehl aus, dann funktioniert der Thread nicht.
Heisst? Compiler Error? Linker Error? Runtime Error? EXceptions?
SimonBTW: Benutze die Code- bzw. C/C++ Tags.
Hallo,
nein das Programm bricht nicht ab. Aber der Switch-Befehlt reagiert nicht.
Erst wenn ich den printf Befehl davor mache, dann fun ktioniert der switch-Befehl.Ist mir völlig schleierhaft.
Wenn ich statts dem switch eine If-Kette aufbaue funktioniert es ebenfalls.
Gruß
Tentone
-
Gratuliere, du hast keine Ahnung von Threads

Es ist ganz klar warum es auf einmal funktioniert wenn du das printf ausserhalb des switch reinmachst: der Compiler weiss nicht so genau was in printf alles abgeht, befürchtet daher dass die Funktion printf den Wert error_flag->Error_Flag ändern könnte, und generiert daher Code dass dieser bei jedem Schleifendurchlauf neu eingelesen wird.Ohne den Aufruf von printf denkt sich der Compiler hui, Error_Flag wird in der Schleife nie geändert, das stecke ich in ein Register, und da lasse ich es, solange bis ein printf() im switch daherkommt, und erst danach lese ich den Wert wieder aus dem Speicher. -> die Schleife läuft "leer" weil die CPU den Wert nie neu aus dem Speicher holt.
Wenn du es ausprobieren willst: du wirst feststellen dass es kaum einen Unterschied macht welche Funktion du an der Stelle wo du printf auskommentiert hast aufrufst, solange es eine Funktion ist über die der Compiler nicht bescheid weiss (also NICHT inline implementiert). Sleep(), GetTickCount(), ... alles ausreichend.
Die brutalo-Lösung ist Error_Flag einfach volatile zu machen. Damit wird es erstmal auch ohne printf funktionieren. Allerdings ist diese Lösung nicht wirklich "korrekt", bzw. nur deswegen korrekt weil unter Windows ganz bestimmte Dinge garantiert werden, und der MSVC bestimmte Dinge genau so macht wie er sie eben macht.
Die "korrekte" Variante wäre ein locking primitive wie z.B. eine CRITICAL_SECTION zu verwenden.
-
Hallo,
ja ich habe bislang noch nicht viel Ahnung. Aber danke für Deine Antwort

Dann kommen wir zu meiner Frage:
in meinem main Programm:
if ( (connect(sock,(struct sockaddr
&address, sizeof(address))) !=0 &&
is_connected==0)
{
check_value=open_socket(Socket_Version, Socket_Data,
&socket_inf); error_flag->Error_Flag=WSAGetLastError();
}
check_value=recv(sock,buf_recieve,BUF,0);wird ja eigentlich (sobald eine Zustandsänderung) eintritt die error_flag geändert.
Jetzt muss ich nur noch meinen thread dazubringen, auf diese Änderung zu reagieren.Danke für Deine Hilfe und bin schon fleißig am Lernen (zum Thema Threads)
Tentone
-
Dann lern bitte auch gleich in Threads im C++ Forum Code-Tags zu verwenden.
-
wird ja eigentlich (sobald eine Zustandsänderung) eintritt die error_flag geändert.
Jetzt muss ich nur noch meinen thread dazubringen, auf diese Änderung zu reagieren.Lies dir bitte alles zum Thema Memory-Model, Threads, Synchronisierung etc. durch was du finden kannst.
Kurzfassung: nur weil du in einem Thread a = 23; sagst ist noch lange nicht garantiert dass diese Änderung in einem anderen Thread auch "sichtbar" ist. Wenn du die "Sichtbarkeit" erzwingen willst musst du sog. Barriers setzen. Wenn du Mutexen (z.B. CRITICAL_SECTION, MUTEX oder auch pthread_mutex) verwendest hast du diese Barriers automatisch beim Lock/Unlock der Mutex. So macht man es auch üblicherweise (also über Mutexen), Code der direkt Barriers verwendet ist eher verpönt, weil schwer zu schreiben (siehe nächster Absatz, das muss man dann auch irgendwie handhaben), und schwer zu lesen/verstehen. Solange man nur unter mit x86/x86_64 arbeitet geht einem einiges durch, aber sobald man versucht seinen Code auf einem PowerPC oder Alpha oder sonstigem Untier zum Laufen zu bekommen fliegt einem schnell was um die Ohren wo man vorher u.U. nichtmal wusste dass man was falsch macht.Nächstes Problem: wenn du a = b; sagst, und ein anderer Thread möglicherweise gleichzeitig b ändert, dann ist nicht garantiert dass a danach einen Wert hat der *jemals* in b gestanden hat. Es könnte z.B. sein dass b "in zwei Teilen" gelesen wird, und sich der Wert zwischen dem Lesen von Teil 1 und Teil 2 geändert hat. Dann hätte a danach vielleicht einen Wert wo Bits 0-15 vom alten Wert von b stammen und Bits 16-31 vom neuen Wert von b. Auch das kann man mit Mutexen verhindern, indem man immer nur einem Thread erlaubt auf b zuzugreifen (MUTual EXclusion, kurz: mutex).
Auf dein Beispiel bezogen könnte das ca. so aussehen:
Mutex g_myMutex; if ((connect(sock,(struct sockaddr *) &address, sizeof(address))) !=0 && is_connected==0) { check_value=open_socket(Socket_Version, Socket_Data, &socket_inf); g_myMutex.Lock(); // damit wir auf "error_flag" zugreifen dürfen error_flag->Error_Flag=WSAGetLastError(); g_myMutex.Unlock(); // damit andere auch wieder drankommen } check_value=recv(sock,buf_recieve,BUF,0); //...Im Thread dann entsprechend:
DWORD WINAPI handle_error(FLAG *error_flag) { for (;;) { g_myMutex.Lock(); // damit wir auf "error_flag" zugreifen dürfen int flag = error_flag->Error_Flag; g_myMutex.Unlock(); // damit andere auch wieder drankommen switch (flag) { case WSANOTINITIALISED : //... } } return 0; }Das ganze ist allerdings etwas viel zu komplex um es hier zu erklären, und es gibt einige Fallstricke. Deadlocks z.B., um einen der "beliebtesten" zu nennen.