Fragen zum richtigen Umgang mit Threads



  • In meinem Programm starte ich einen Thread, der dazu da ist eine noch unbestimmte Anzahl von weiteren Threads zu starten. Wärend der Laufzeit ermittelt das Programm wieviele weitere Threads gestarted werden müssen, manchmal bis zu 10000, die Anzahl der gleichzeitigen Threads kann so zwischen 10 und 200 liegen. Muss ich mir in meinem Programm arrys definieren die die Handle zu den Threads und den Identifier beinhalten so etwa:

    HANDLE	myThread[201];
    DWORD	myThread_ID[201];
    

    Ich dacht mir, daß ich so vorgehe und prüfe welcher von den nun bis zu 200 gestarteten thread beendet ist dan starte ich einen weiteren, so daß immer eine feste maximal Zahl von Threads läuft.

    Also meine Thread starte ich ja z.B. so

    myThread[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)myFunction, 0, 0, &myThread_ID[0]);
    

    die aufgerufene Funktion sieht doch dann in etws so aus:

    void myFunction(void){
    :
    :
    :
    ExitThread(0);
    

    wenn die Funktion fertig ist beendet sich der Thread und der Exitcode ist in diesem Fall "0". Ja aber wohin wird der Exiccode hingegeben. Wie weiss ich anhand dem Handle oder dem Thread ID welcher nochj aktiv ist, Leider raff ich den Zusammenhang nicht Recht. Was passiert eigentlich wenn der Thread nicht mit ExitThread beendet wird?



  • Hallo,

    1. Der Thread Exit Code kann mit der WinAPI Funktion abgefragt werden.

    BOOL GetExitCodeThread( 
      HANDLE hThread, 
      LPDWORD lpExitCode
    );
    

    2. Die Signatur der Funktion, die auf einem anderen Thread ausgeführt wird, sieht so aus:

    DWORD WINAPI ThreadProc(
      LPVOID lpParameter
    );
    

    Dann muss auch nicht nach LPTHREAD_START_ROUTINE gecastet werden.
    3. Wenn Du die Thread ID nicht benötigst, kannst Du auch NULL übergeben (beim aufruf von CreateThread).
    4. Ich denke, dass soviele Threads nicht sinnvoll sind.
    Es gibt zwei Gründe für Threads:
    a.) Man möchte erreichen, dass z.B. das GUI trotzdem reagiert, während eine Operation lange dauert. (Dabei wird z.B. eine CPU zeitlich aufgeteilt.)
    b.) Man möchte erreichen, dass eine bestimmte Operation auf mehrere CPU's verteilt wird, und somit die Operation parallelisiert wird. Dies kann mit Threads erreicht werden. (Aber nur soviele wie CPU's vorhanden sind.)

    Ich kenne dein Anforderung nicht, aber ich vermute, das Problem könnte auch mit einem anderen Ansatz gelöst werden. Was möchtest Du erreichen?

    Zudem möchte ich anmerken, dass viele Threads so einiges mitbringen, was nicht erwünscht ist (ContextSwitching, Memory verbrauch durch ThreadStack, ...).

    Grüsse
    Simon



  • Ok, ich erkläre es mal im Groben. Mein Programm scannt Spiele Server. Eine vorgegebene List mit einer variablen Anzahl von IP Adressen (z.Z. bis zu 20480) wird der Reihe nach gescannt und die Informationen grafisch aufgearbeitet. Ich habe die ganze Zeit die Threads über einen „Masterthread“ so gestartet:

    //ScanThread zig mal gestartet
    void Query_Server(int server_id){
    	:
    	:
    	EnterCriticalSection(&myCriticalSection);
    //	Kritischer Code!!!!!!!!!!!!!!!!!!!!!!!
    	LeaveCriticalSection(&myCriticalSection);
    :
    	:
    	ExitThread(0);
    }
    
    //HauptThread 1x gestartet
    void myFunction(void){
    
    	HANDLE	myThread;
    	DWORD		myThread_ID;
    	:	
    	:
    	:
    	:
    	for (server_id = 0; server_id < MAX_SERVER; server_id++){
    		MyThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Query_Server, (void *)server_id, 0, &MyThread_ID);
    		if(MyThread){
    			CloseHandle(MyThread);
    	}
    	Sleep(1000/server_per_second);
    	ExitThread(0);
    }
    

    Ähm, ich sollte dazusagen, daß das Programm soweit gut läuft, nur wenn es während der Scanphase mit ALT+F4 oder über das Menü beendet wird, kann es zu Überschneidungen kommen, weil schon Daten gesichert werden, aber irgendwelche Nachzügler Threads noch Daten schicken dann crasht mein Programm. Ich denke ich sollte an dieser Stelle überprüfen, welche Threads noch aktiv sind und erst mit der Sicherung der Daten anfangen, wenn auch der letzte der gestarteten Threads sich beendet hat. Ja das ist dann das Problem das ich habe, wie gehe ich da am geschicktesten dran.



  • indem du z.B. in deinen Thread (in denen du vermutlich auch zyklische abfragen hast) auch bei jedem zyklus darauf wartest das ein abbruchsignal kommt ... und vor verlassen des thread eine dem thread zugeordnete variable veränderst .... was weis ich, eine finished variable z.B. die der Thread kurz vorm beenden auf true setzt ... im main wartest du halt nur ab das alle variablen auf true sind ..... stichwort EVENT an dieser stelle, macht dads ganze vll. noch ansehnlicher


  • Mod

    Vermeide CreateThread, wenn Du CRT Funktionen verwendest. Das erzeugt Leaks in der CRT.
    Verwende immer _beginthread(ex)



  • @Ceos, ja das mit der Variablen hab ich mir auch schon so gedacht, jetzt weis ich nicht wie es sich verhält, wenn sich ein Thread mal verabschiedet, und die Var dann immer noch gesetzt ist, da müsste dann halt ein Timer die Sache beenden.

    @Martin, das mit der Verwendung von "_beginthread(ex)" hab ich auch mal in der MSDN Docu entdeckt, kannst du mir sagen was CRT Funktionen sind?



  • Das sind die C-Runtime-Library-Funktionen, also alles, was der C-Standard umfaßt.



  • Das heist also, wenn ich im meinem Thread strcpy, sprintf oder dergleichen verwende sollte ich den Threat mit "_beginthread(ex)", wenn ja nach welche Kriterein benutze ich dann um "_beginthread" oder aber "_beginthreadex" zum Starten zu verwenden?


  • Mod

    • Holgi * schrieb:

    Das heist also, wenn ich im meinem Thread strcpy, sprintf oder dergleichen verwende sollte ich den Threat mit "_beginthread(ex)",

    Ja!

    wenn ja nach welche Kriterein benutze ich dann um "_beginthread" oder aber "_beginthreadex" zum Starten zu verwenden?

    Ich verstehe Deine Frage nicht. Die Frage ist was Du benötigst. _beginthreadex benötigst Du z.B. um einen Thread suspended zu erzeugen...



  • wenn sich ein Thread mal verabschiedet

    musst du deinen code halt doppelt und 3 fach absicher so mit try catch usw. ansonsten fällt mir da adhoc nur noch ein das du regelmäig einer variable einen zeitwert übergibst, den du auf 0 setzt wenn der thread beendet ... ansonsten möglichst regelmäßig updaten und den thread abschiessen wenn er 5 sek nicht reagiert .... dabei musst du aber beachten das z.B. das connect nicht zu lange dauert (non blocking mode benutzen kann da abhilfe schaffen)



  • Übrigens erhält jeder erzeugte Thread einen Stack.
    Die Grösse kann bei CreateThread (und auch bei beginthread..) angegeben werden.
    Wird 0 angegeben (wie bei Dir) wird der Stack auf 1MB festgelegt.

    Das sind bei 200 Threads alleine wegen den Thread Stacks schon 200MB die reserviert sind.

    Ich halte soviele Threads nicht für sinnvoll (nur schon wegen den Context Switches und dem Memory Verbrauch).

    Für IO gibt es mehrere Lösungen, wie man mit deutlich weniger Threads auskommt (Overlapped IO, APC, IO Completion Ports).

    Grüsse
    Simon



  • Ja, da hast du bestimmt Recht. Ich werde nachdem ich dieses Problem hier gelöst habe, versuchen alternative einen anderen Weg einschlagen und damit den Serverscan zu realisieren. Leider bin ich auf den Gebieten wie du sie anspricht überhaut nicht bewandert und so werde ich wohl noch einige Zeit brauchen bis ich mich einigermassen in der Materien auskenne. Also danke erstmal für die Antworten und Denkanstösse.



  • Speicherverbrauch ist normal kein Problem bei 200 Threads, und Context-Switches tun auch nicht wirklich soviel teurer als Dispatching über IO Completion Ports o.Ä.

    Bei 1000-10.000 Connections sieht die Sache allerdings schonwieder ganz anders aus - das bekommt man mit Threads (1 Thread pro Connection meine ich) kaum noch irgendwie hin.



  • stichwort select(...) und dann die ankommenden daten nacheinander verarbeiten (evtl. ne datenstruktur in einer map<SOCKET,MyServerData> speichern) brauch nur einen thread ... blöd natürlich wenn du 10000 sockets hast und die zeitkritisch reagieren sollen ...



  • So und jetzt hab ich doch noch eine Frage, und zwar mein Controll thread der die anderen threads kontrolliert, ob sie noch laufen, ob die maximalzahl gestarted ist, etc. Wie kann ich es anstellen das dieser Thread eine höhere Priorität oder mehr cpu Zeit wie immer man dazu sagt. Also ich weiss noch nicht ob ich das überhaupt benötige, aber zu wissen was geht und was nicht wäre schon mal hilfreich.



  • Bissi MSDN Lesen schadet nicht:

    // in dem Thread der die höhere Priorität bekommen soll:
    ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
    

Log in to reply