Thread-Nutzung korrekt?


  • Mod

    Es muss doch irgendeine logische Bedingung geben, bei der die Threads beendet werden sollen. Die Threads müssen selbstständig diese Bedingung prüfen und ggf. dann selber zum Ende kommen. Du beendest die Threads nicht von außen.



  • Ich hatte ja zuerst angenommen, dass der Thread sich selbst beendet sobald er seine Funktion abgearbeitet hat
    Diese Funktionen haben beide eine while-Schleife. Die wird verlassen sobald die laufende Runde beendet wurde und damit endet dann auch die Funktion. Das passiert auch so wie es soll. Aber der Thread bleibt trotzdem vorhanden, er tut dann nur nichts mehr.



  • Ich würde vorschlagen, dass du mal deinen Code postest mit dem du Threads erzeugst. Auf anhieb würde ich vermuten, dass deine Threads sich schon beenden, du aber immer neue Thread Instanzen erstellst.


  • Mod

    Mein Schuss ins Blaue: Fehlendes join.



  • Das hier wäre der Teil der für die Funktionsaufrufe zuständig ist.

    while(true) {
    
    	RoundFunctions RoundFunctions;
    
    	if(roundStart) {
    
    		RoundFunctions.startNewRound(userSettings["Level"], userSettings["Difficulty"]);
    
    		std::thread t1(&RoundFunctions::doDayNightCycle, &RoundFunctions, std::ref(config), std::ref(userSettings));
    		t1.detach();
    		std::thread t2(&RoundFunctions::doSpecialEvents, &RoundFunctions, std::ref(config), std::ref(userSettings));
    		t2.detach();
    
    		roundStart = false;
    
    	}
    
    }
    

    Bei jedem Start bekomme ich dann zwei zusätzliche Threads erstellt.

    Mein Schuss ins Blaue: Fehlendes join.

    Hab ich tatsäcjlich nicht. Liegt aber in dem Fall daran, dass dann das ganze nicht funktioniert wie ich will - beide Funktionen werden dann wieder nur "nacheinander" abgelaufen...


  • Mod

    Und jetzt noch bitte die aufgerufenen Funktionen und eine Erklärung, wie du feststellst, dass die Threads überhaupt noch leben. Oder anders gesagt: Wieso lieferst du nicht endlich mal ein vollständiges Minimalbeispiel?



  • und eine Erklärung, wie du feststellst, dass die Threads überhaupt noch leben.
    

    Ich lasse es ja über Visual-Studis im Debug-Modus laufen. Wenn ich die Ausführung beende werden mir auch alle Threads angezeigt die beendet wurden. In der zwanzigsten Runde ist die Liste extrem lang - also nehme ich an, dass diese Threads alle noch vorhanden gewesen sind.

    Wieso lieferst du nicht endlich mal ein vollständiges Minimalbeispiel?
    

    Weil man mich nur nach dem Teil gefragt hat in dem ich die Threads erstelle und ich nicht dachte, dass es relevant ist was in den Funktionen steht.

    Hab es nun so gelöst, dass ich die Threads einmalig vor der While-Schleife erstelle. Den Rest (ob und wann die Funktion ausgeführt wird) regel ich nun innerhalb der Funktion selber, anhand des Rückgabewertes aus der Rundenfunktion.

    Da es mich aber trotzdem interessieren würde, wo da das Problem liegen könnte hab ich es nochmal in meinem Testprogramm ausprobiert wo dasselbe Problem auftritt. Den ganzen Code poste ich hier mal vielleicht finden wir die Ursache ja noch:

    #define WIN32_LEAN_AND_MEAN
    #include <iostream>
    #include <string>
    #include <Windows.h>
    #include <map>
    #include <thread>
    
    class TestFunctions{
    public:
    	TestFunctions();
    	void TestFunctions::function1(std::map<std::string, std::map<std::string, std::map<std::string, unsigned int>>> testMap1, std::map<std::string, std::map<std::string, std::map<std::string, unsigned int>>> testMap2);
    	void TestFunctions::function2(std::map<std::string, std::map<std::string, std::map<std::string, unsigned int>>> testMap1, std::map<std::string, std::map<std::string, std::map<std::string, unsigned int>>> testMap2);
    	~TestFunctions();
    
    private:
    
    };
    
    TestFunctions::TestFunctions() {
    }
    
    void TestFunctions::function1(std::map<std::string, std::map<std::string, std::map<std::string, unsigned int>>> testMap1, std::map<std::string, std::map<std::string, std::map<std::string, unsigned int>>> testMap2) {
    
    	SYSTEMTIME Time;
    	GetSystemTime(&Time);
    	long currentTime = (Time.wSecond * 1000) + Time.wMilliseconds;
    	long endTime = currentTime + testMap1["Global"]["Config"]["Duration"];
    
    	while (currentTime < endTime) {
    		// Ich tue hier wirklich gar nichts! Nur eine Dummyschleife
    		GetSystemTime(&Time);
    		currentTime = (Time.wSecond * 1000) + Time.wMilliseconds;
    	}
    
    	return;
    
    }
    
    void TestFunctions::function2(std::map<std::string, std::map<std::string, std::map<std::string, unsigned int>>> testMap1, std::map<std::string, std::map<std::string, std::map<std::string, unsigned int>>> testMap2) {
    
    	SYSTEMTIME Time;
    	GetSystemTime(&Time);
    	long currentTime = (Time.wSecond * 1000) + Time.wMilliseconds;
    	long endTime = currentTime + testMap1["Global"]["Config"]["Duration"];
    
    	while (currentTime < endTime) {
    		// Ich tue hier wirklich gar nichts! Nur eine Dummyschleife
    		GetSystemTime(&Time);
    		currentTime = (Time.wSecond * 1000) + Time.wMilliseconds;
    	}
    
    	return;
    
    }
    
    TestFunctions::~TestFunctions() {
    }
    
    int main() {
    
    	std::map<std::string, std::map<std::string, std::map<std::string, unsigned int>>> testMap1;
    	std::map<std::string, std::map<std::string, std::map<std::string, unsigned int>>> testMap2;
    
    	testMap1["Global"]["Config"]["Duration"] = 500;
    	testMap2["Global"]["Config"]["Duration"] = 500;
    
    	bool start = true;
    	TestFunctions TestFunctions;
    
    	int i = 0; // Anzahl der Threads die über die ganze Laufzeit erstellt werden als Vergleichswert (wenn beendete Threads bei Programmende = i dann wurde nie ein Thread beendet?)
    
    	while(true) {
    		std::thread t1(&TestFunctions::function1, &TestFunctions, std::ref(testMap1), std::ref(testMap2));
    		//t1.join();
    		t1.detach();
    		std::thread t2(&TestFunctions::function2, &TestFunctions, std::ref(testMap1), std::ref(testMap2));
    		//t2.join();
    		t2.detach();
    
    		i = i + 2;
    
    		std::cout << i << std::endl;
    
    	}
    
    	return 0;
    }
    

    So läuft es auch in meinem Spiel /einziger Unterschied, die while-Schleifen in den Funktionen haben tatsächlich eine echte Aufgabe, der Effekt ist aber derselbe wie hier).



  • while(true) {
    		std::thread t1(&TestFunctions::function1, &TestFunctions, std::ref(testMap1), std::ref(testMap2));
    		//t1.join();
    		t1.detach();
    		std::thread t2(&TestFunctions::function2, &TestFunctions, std::ref(testMap1), std::ref(testMap2));
    		//t2.join();
    		t2.detach();
    
    		i = i + 2;
    
    		std::cout << i << std::endl;
    
    	}
    
    	return 0;
    }
    

    Ich kenn mich zwar nicht wirklich mit Threads aus, aber sollte das join nicht am Ende kommen, um auf das Ende der beiden Threads zu warten?

    while(true) {
    		std::thread t1(&TestFunctions::function1, &TestFunctions, std::ref(testMap1), std::ref(testMap2));
    
    		t1.detach();
    		std::thread t2(&TestFunctions::function2, &TestFunctions, std::ref(testMap1), std::ref(testMap2));
    
    		t2.detach();
    
    		i = i + 2;
    
    		std::cout << i << std::endl;
    
            t1.join();
            t2.join();
    	}
    
    	return 0;
    }
    


  • detach und danach join ist Blödsinn, entweder oder!

    https://stackoverflow.com/questions/37015775/what-is-different-between-join-and-detach-for-multi-threading-in-c

    Also: erst die threads alle erzeugen, dann alle joinen.

    Den Code von Gedankenausbruch verstehe ich nicht. Was soll mit der while(true)-Schleife erreicht werden? Den Rechner mit threads vollspammen?



  • Den Code von Gedankenausbruch verstehe ich nicht. Was soll mit der while(true)-Schleife erreicht werden? Den Rechner mit threads vollspammen?
    

    Ja, genau das war der Sinn der Sache.
    Die Funktionen die aufgerufen werden laufen exakt 500ms. Danach sollte der Thread beendet werden. Fragen waren: Warum werden sie nicht beendet, wie sorge ich dafür, dass sie beendet werden, wenn ihre Funktion ihr Ende erreicht hat?

    Schrieb ich aber alles schon.



  • Also generell würde ich dir empfehlen kurz die Wörter "Threadpool, Worker, Listener, Dispatcher" in deine persönliche Lieblingssuchmaschine einzutippen, dort wirst du bestimmt etwas finden.

    Meine Interpretation:

    Deine Threads beenden sich vermutlich, aber es werden schneller welche erzeugt, wie Sie sich beenden können. Die joins sollten am Ende kommen und soweit ich verstanden habe, brauchst du (in diesem Fall) kein detach.

    Auch möglich:
    Bei jedem Erstellen eines Threads wird ein globaler counter um eins inkrementiert. Bei jedem Beenden eines Threads wird dieser counter dekrementiert.

    Somit kannst du eine Maximalzahl an Threads einstellen, wenn nur neue Threads erzeugt werden, falls nicht schon genügen da sind.

    Diese Variable ist gemeinsam genutzt und braucht irgendeine Art Mutex oder gutes Design (bin mir nicht mehr sicher, aber präfix inkrement und dekrement sollten atomare operationen sein, und werden dadurch nicht unterbrochen, also ++threadAnzahl und --threadAnzahl verwenden)


Anmelden zum Antworten