Synchronisationsproblem mit Threads: Denkfehler?
-
Ja, im Prinzip hast du recht.
Was jetzt aber witzigerweise passiert ist folgendes:
Die Thread-Schleifen brauchen so lange, um von SetEvent zum unteren WaitForSingleObject zu kommen, dass in der Zeit das Event gesetzt und zurückgesetzt wurde. Wie kann ich denn sicherstellen, dass er auch wirklich wartet und nicht nur in der Zeile vorher ein Event rausgibt?void PMBodyThread::Execute(void *arg) { while(true) { WaitForSingleObject(m_syncHandle,INFINITE); ((PMBodyInterface*)arg)->computeSound(); SetEvent(m_readyHandle); WaitForSingleObject(m_sync2Handle,INFINITE); } }Kann mir jemand sagen, wie das mit PulseEvent funktioniert? Oder automatisch resettenden Events? Die sollten doch eigentlich dafür gemacht sein, oder? Hab aber das Gefühl das sie nicht funktionieren....
-
Also, ich werd wahnsinnig.
Ich hab ihm jetzt noch eine weitere Sicherheitsstufe geschenkt. Das ganze sieht so aus:while(true) { SetEvent(m_ready2Handle); WaitForSingleObject(m_syncHandle,INFINITE); ResetEvent(m_ready2Handle); ((PMString*)arg)->getOutput(); SetEvent(m_readyHandle); WaitForSingleObject(m_sync2Handle,INFINITE); ResetEvent(m_readyHandle); }Was jetzt passiert? Die Threads bleiben bei der vorletzten Reihe hängen, weil der Hauptthread nicht auf die SetEvents reagiert und auf die wartet. Falls jemand noch irgendeine andere Lösung für das gewurschtel hat?!???
Ich brauch ne Pause
Schönen Abend!
Sören
-
ich könnt jetzt versuchen mich an meine paralleldatenverabeitungsvorlesungen zu erinnern ....aber das artet wieder in kopfschmerz aus .... darf man fragen wie du dir die abarbeitung der threads genau vorstellst ? diese parallelausführung und zusammenführung der threads garantiert dir zwar das alle threads ihre berechnung gleichzeitig abschliessen aber du verschwendest natürlich rechenzeit während die schnellen auf die langsamen threads warten ...
aber an deiner stelle würd ich die threadsteuerung mehr zentralisieren und weniger die threads sich gegenseitig freigeben lassen
wie gesagt ich kann mir leider nicht vorstellen was genau du berechnest
-
Also wenn Du immer auf alle Threads wartest (und da lohnen sich höchstens zwei) Frage ich mich wirklich ob hier irgendwas schneller berechnet wird. Bei dem Aufwand, den Du hier treibst.
IMHO benötigst Du nur 4 Events,
- StartEvent (signalisiert den Threads den Start),
- ReadyForWorkEvent für jeden Thread, der sagt ich warte auf Arbeit.
- DoneEvent signalisert aus dem Hauptthread, dass die Arbeit getan ist.
- NextJobEvent signalisiert den Threads wieder in die Startphase zu gehen.Alle Events sind zurück gesetzt.
1. Alle Threads setzen Ihr ReadyForWorkEvent und warten auf StartEvent
2. Haupthread wartet das alle Threads ReadyForWork sind.
3. Hauptthread reseted NextJobEvent (könnte bei mehreren Dürchläufen gesetzt sein (siehe unten)
4. Haupt Thread setzt StartEvent
5. Hauptthread wartet auf alle DoneEvents
6. Worker setzen alle irgendwann DoneEvent und warten nun auf NextJobEvent Event.
7. Sind alle DoneEvents vorhanden, resetted der Hauptthread das StartEvent und setzt NextJobEvent Event.
8. Alle Worker laufen wieder los und es geht bei 1. weiter. Mit dem Unterschied, dass aktuell noch NextJobEvent gesetzt ist. Das klärt sich bei 3Wichtig ist hier, dass die signalsierenden Events nicht zurückgesetzt werden bis alle Threads wieder einen definierten Status ereicht haben.
Das ganze kann auch leichter gehen...

-
Ja vielen Dank!
So hab ich mir das bei meinem letzten Posting gedacht, und nachdem ich einen Schreibfehler korrigiert hatte, lief es auch (ich sollte meine Events besser benennen...) Leider nicht schnell genug, wobei ich aber noch austesten muss, ob das ganze Thread gewurschtel einen zu großen Overhead mit sich bringt, oder die ganze Sache allgemein zuviel Leistung verschlingt.Was ich mir im Prinzip gedacht hatte war folgendes: Es soll eine Gitarre mit Physical Modeling berechnet werden. Da bis auf die (mechanischen) Schnittstellen, Saiten und Korpus getrennt voneinander berechnet werden können, soll jeder Berechnung ein Thread zugeordnet werden, der bei Bedarf von Windows auf meine BEIDEN GELIEBTEN PROZESSORKERNE verteilt werden kann. Nun müssen aber natürlich Saiten und Korpus synchron miteinander agieren. Nützt ja nichts, wenn der Korpus schon 10mal rechnet mit dem selben Eingangswert, der von der Saite kommt. Eigentlich könnte man das auch in einem einzigen Thread machen und ich berechne einfach zuerst die Saiten und dann den Korpus. das hätte nur den Nachteil, dass man das nicht auf zwei Kerne verteilen kann.
Ist das jetzt wenigstens logisch durchdacht, oder bin ich mal wieder auf dem Holzweg?
Viele Grüße und danke für alles
Sören
P.S. Habt ihr denn einen Tipp wie das leichter funktioniert?
-
Dann verstehe ich Deinen Ansatz nicht. Natürlich darfst Du dann die Berechnung nur einmal ansetzen.
Es lohnen sich auch nur so viele Threads wie Du auch Kerne hast, also aktuell 2-4, je nach Hardware.
Zerlege Deine Berechnungen in Objekte und lass diese eben auch nur dann berechnen wenn es nötig ist. Das Verfahren was wir hier verwendet haben eignet sich eher Paralellberechnung für ein und den selben Rechnvorgang.
Vorgänge die bereits berechnet sind, darfst Du eben nicht neu berechnen.
Wie sollen wir Dir hier helfen?
-
Also, mal abgesehen davon, dass der ganze Thread-Wust mehr bremst als nützt ist die Sache doch klar oder? Um Missverständnisse zu vermeiden:
Alles was ich will, ist, zwei unahängige Berechnungen, die pro Zeitsample einmal durchgeführt werden müssen, auf zwei Threads und somit zwei Kerne zu verteilen. Alles, was darüber hinaus passiert ist, ist wohl eher meiner programmiertechnischen Unkenntnis als bewusstem Handeln zuzuschreiben. Kann sein, dass ich euch damit verwirrt habe?
Die Berechnungen sind ja in Objekten angelegt, alles ganz easy. Im Single-Thread sieht das so aus:m_theBody->computeSound() m_theString->computeSound()Hab es nur nicht anders geschafft zu sagen: Thread1 bitte einmal, Thread 2 bitte einmal, und nächstes Sample!
Vielleicht hätte ich einfach die Frage stellen sollen, wie ich diesen Code auf zwei Kerne verteilen kann? Tut mir leid, dass ich das nicht eher klar gemacht habe...
Grüße
Sören
-
- Dann erzeuge eine Liste mit Objekten die berechnet werden sollen. Abgesichert durch eine Critical Section.
- Erzeuge soviele Threads wie Kerne vorhanden sind.
- Jeder Thread holt sich ein Element aus der Liste (abgesichert durch eine Critical Section) und fürht die Berechnung durch.
- Wenn Die Liste leer ist. terminieren die Threads, oder warten einfach bis wieder was in der Liste ist.
-
Ok, das hört sich gut an.
Würde das dann etwa so aussehen?:while(true) { EnterCriticalSection(&cs); object=list->pop(); LeaveCriticalSection(&cs); object->computSound(); }Wie warte ich auf ein Objekt in der Liste?
Jetzt muss der HaupThread aber immer noch auf das Ergebnis der Berechnungen warten.
Das sieht mir wieder nach ein paar Events aus?
Vielen Dank für deine Mühe!
Grüße
Sören
-
Durch ein Event! Derjendige, der etwas in die Liste packt, setzt das Event. Der Thread, der das letzte Element rausholt. Setzt den Event zurück!
So schwer?Das Objekt, dass Du von der Liste Popst kann doch einen Event enthalten. Auf diesen Event muss natürlich der nutzende Thread warten...
-
Jaja, irgendwie hätte ich das schon hinbekommen, aber das sieht mir dann nicht unbedingt schneller aus als die Version, die wir schon haben, oder?
Am laufen hab ichs ja, es bremst nur mehr als es nützt.
Grüße
Sören
-
Wenn die ARbeitsabschnitte zu klein sind, hast Du mehr Overhead als es eben Effekt bringt.
Das ganze bringt es eben nur wen die Threads sehr unterschiedliche Dinge tun und eben auch warten oder eben auch Kalkulationen durchführen, die lange genug dauern.Wenn Du jedesmal neue Threads startest ist der Overhead immens...
-
Ne, neue Threads starten kommt nicht in Frage, klar. Aber die Arbeitsschritte sollten zumindest bei der Saite relativ groß sein. Da habe ich ne Schleife mit 60 durchgängen und einigen Additionen und Multiplikationen. Der Korpus ist von der Last her etwas unregelmäßig (was leider nicht zu ändern ist), mal schauen.
Ok, ich glaube, wir können den Thread
abschließen.
Vielen Dank für deine Anregungen und Hilfe!
Sören