![]() |
Wie kann man das Ausführen der Threads Priorisieren
Ich habe einen "Hauptthread" und mehrere "Nebenthreads". Alle greifen auf eine TThreadlist zu. Jetzt möchte ich den Zugriff auf TThreadlist priorisieren. Kann mir jemand sagen, wie man das macht?
Details: HauptThread TThreadlist.lock was heraus holen TThreadlist.unlock Do something NebenThread1 NebenThread2 NebenThread3 NebenThread4 : NebenThread_n alle rufen folgende Funktion auf INPUT(data) TThreadlist.lock was hinein legen TThreadlist.unlock Der HauptThread soll die TThreadlist öffnen und schließen. Dann soll nur EINER der Nebenthreads TThreadlist öffnen und schließen. Dann soll wieder der HauptThread die TThreadlist öffnen und schließen. Jetzt der nächste Nebenthread u.s.w. bis es wieder von vorne anfängt. |
AW: Wie kann man das Ausführen der Threads Priorisieren
Hmmmm - es sollen also die Nebenthreads warten "bis sie dran sind"? Widerspricht das nicht dem Konzept der Threads?
Ich löse sowas eigentlich immer über Thread.Priority - der wirklich wichtige bekommt eben mehr Priorität. Wenn es wirklich wichtig ist, daß immer EINMAL der HauptThread und dann EINMAL einer der NebenThreads schreibt, dann würde ich mir überlegen, ob das Design richtig ist und ob's nicht gescheiter ist, das alles über den Hauptthread abzuwickeln ist, da du da zwangsläufig eine Wartesituation zusammenbringst. Nur mal aufgrund der Informationen ins Blaue geraten, GRL |
AW: Wie kann man das Ausführen der Threads Priorisieren
Hallo,
nicht ganz, vielleicht sollte ich noch erwähnen, dass sich die Nebenthreads in DLLs befinden und es nicht vorhersehbar ist, wann sie schreiben wollen. Noch genauer: die DLLs füllen die TThreadlist mit Telegrammen und der Hauptthread versendet sie per TCP. Problem: Wenn ich die Nebenthreads nicht in ihre Schranken weise, schreiben die so viel, dass ich keine Zeit mehr habe um die Daten zu versenden! |
AW: Wie kann man das Ausführen der Threads Priorisieren
Zitat:
Zitat:
|
AW: Wie kann man das Ausführen der Threads Priorisieren
Warum schreiben die alle in die gleiche Liste? Mach doch für jeden Thread eine eigene Liste, und dann arbeitest du die Listen im Hauptthread nach Priorität ab.
|
AW: Wie kann man das Ausführen der Threads Priorisieren
Also generell kann man so etwas mit einem
![]()
Delphi-Quellcode:
Der Hauptthread ruft jetzt immer
type
TFoo = class private FThrottle : TEvent; FCS : TCriticalSection; procedure ReleaseThrottle; public constructor Create; destructor Destroy; override; procedure DoSomethingThrottled; procedure DoSomethingDifferent; end; implementation { TFoo } constructor TFoo.Create; begin inherited Create; FThrottle := TEvent.Create( nil, False, False, '' ); end; destructor TFoo.Destroy; begin FThrottle.Free; FCS.Free; inherited; end; procedure TFoo.DoSomethingDifferent; begin FCS.Enter; try // Aus der Liste holen finally FCS.Leave; end; ReleaseThrottle; // dem nächsten Thread den Zugang erlauben end; procedure TFoo.DoSomethingThrottled; begin if FThrottle.WaitFor = TWaitResult.wrSignaled then begin FCS.Enter; try // In die Liste Legen finally FCS.Leave; end; end; end; procedure TFoo.ReleaseThrottle; begin FThrottle.SetEvent; end;
Delphi-Quellcode:
auf und alle SubThreads rufen
DoSomethingDifferent
Delphi-Quellcode:
auf.
DoSomethingThrottled
Der Event sorgt dafür, dass immer nur ein Thread durchschlüpfen kann und der nächste Thread, wenn im
Delphi-Quellcode:
das
DoSomethingDifferent
Delphi-Quellcode:
aufgerufen wird.
ReleaseThrottle
Über Sinn und Unsinn mag ich hier jetzt nicht diskutieren, aber es geht ;) PS Die CriticalSection ist natürlich bei einer ThreadList unnötig |
AW: Wie kann man das Ausführen der Threads Priorisieren
Zitat:
Denn selbst wenn ein Thread eine geringere Prio hat, wie ein anderer Thread, so kann es dennoch sein, daß der mit der geringeren Prio genauso schnell oder sogar schneller ist. |
AW: Wie kann man das Ausführen der Threads Priorisieren
Das mit den Events ist ein sehr interessanter und konstruktiver Vorschlag, danke.
Vielleicht habe ich mich mit dem Wort "Priorität" falsch ausgedrückt. Ich meinte nicht die Thread-Priorität. Man kann es auch einfach als Umschalter sehen zwischen füllen und leeren. Und schließlich muss mehr geleert werden als gefüllt, sonst funktioniert es nicht. Da ist es auch OK, wenn ein Füller wartet. Also ganz primitive betrachtet eine einfache Serialisierung. Jeder DLL eine eigene Liste zu geben würde den Aufwand produzieren, dass wieder die DLL Listen gelockt und verwaltet werden müssten. Man kann es auch mal ganz extrem sehen (was auch möglich wäre): Es gibt 100 Nebenthreads die fast gleichzeitig schreiben wollen. Da wäre der Hauptthread lange am warten, bis er wieder dran kommt (in Versuch nachgewiesen!) |
AW: Wie kann man das Ausführen der Threads Priorisieren
Das mit dem Event kann man auch umdrehen.
Wenn der Sende-Thread lesen möchte, dann wird der Event zurückgesetzt und alle Empfangs-Threads werden durch den Event aufgehalten und können erst mal nicht mehr schreiben. Ist der Sende-Thread fertig mit lesen, dann setzt der wieder den Event und alle schreiben wieder lustig in die Liste. Dazu muss der Event wie folgt initialisiert werden:
Delphi-Quellcode:
TEvent.Create(
nil, True, {ManualReset} True, {InitialState} '' ); |
AW: Wie kann man das Ausführen der Threads Priorisieren
Zitat:
Zitat:
Edit: Falls es nicht klar war, jede Liste hätte natürlich auch ihr eigenes Lock. Sonst wäre die Sache witzlos. |
AW: Wie kann man das Ausführen der Threads Priorisieren
Zitat:
Und wirklich viele Prioritäts-Stufen hat man nicht (ist auch unnötig), so dass die echte Kontrolle immer selber erfolgen sollte. Die Priorität ist nur unterstützend zu sehen und hilft dem Betriebssystem beim Verteilen der Zeitscheiben. |
AW: Wie kann man das Ausführen der Threads Priorisieren
Aber wenn man 100 laufende Threads auf z.B. 4 Kerne verteilen muss, dann ist das Problem wirklich, dass man 100 laufende Threads auf 4 Kerne verteilen muss, und nicht mehr, dass einer der Threads zu langsam ist. Und dann sollte man lieber auf den Scheduler des Betriebssystems vertrauen und ihm die entsprechenden Informationen liefern statt seine eigene Suppe zu kochen.
|
AW: Wie kann man das Ausführen der Threads Priorisieren
Ähm, er hat nicht berichtet, dass sein System eingefroren ist, und das wäre der Fall, wenn 100 Threads die volle Aufmerksamkeit der CPU beanspruchen würden.
Können die auch gar nicht, da alle Threads in eine Liste schreiben wollen und das können die nun mal nicht gleichzeitig. Also sind 99 Threads am Warten und 1 Thread am Schreiben. Sein Problem ist jetzt, dass er mit dem Thread zum Weiterreichen (Lesen aus der Liste) nicht mehr so richtig dazwischenkommt. Also braucht er eine Logik, die dieses Auslesen priorisiert. Jetzt stehen 99 Schreib-Threads an der CriticalSection und der Lese-Thread hängt hinten dran und muss abwarten, bis diese 99 abgearbeitet sind. Wenn die Schreib-Threads jetzt eine geringere Priorität bekommen, dann könnte es sogar noch langsamer werden. Ich glaube das ist nicht gewollt ;) |
AW: Wie kann man das Ausführen der Threads Priorisieren
Zitat:
Ich meine nur, das ist ein ganz anderes Problem als das Problem, dass der Main-Thread nur in sehr großen Abständen mal eine Zeitscheibe abbekommt. Es sind zwei verschiedene Probleme. |
AW: Wie kann man das Ausführen der Threads Priorisieren
Hi Sir Rufo,
danke für den 2. Hinweis. Genau so brauche ich es. Denn wenn es nichts zu senden gibt, sollen die Clients in die Liste ja ungehindert schreiben können. Damit wäre auch der Charakter des Multithreading wieder vorhanden, eben nur mit einen Thread-König, der das sagen hat. So wie ich dem Thread-König sein Thread-Sleep einstelle, verschiebe ich die Zeitscheibe für schreiben und lesen. Effekt ganz nebenbei: Die Clients schreiben nicht nur, sondern packen die Daten auch in schon vorhandene Telegramme, also packen Telegramme voll damit der Overhead zu den Nutzdaten klein bleibt. Du siehst, es ist eine feine Abstimmung, damit es richtig funktioniert. Aber jetzt habe ich wenigstens eine Stellschraube! |
AW: Wie kann man das Ausführen der Threads Priorisieren
Nur so als Denkanstoß:
Lasse die Schreibe-Threads in eine Warteschlange A schreiben, erzeuge einen weiteren Thread, der aus dieser Warteschlange A jeweils blockweise in eine andere Warteschlange B überträgt. Der "HauptThread" entnimmt seine Aufträge aus B, und bearbeitet sie. Wenn das noch nicht reicht, kann auch der Hauptthread Blockweise alle in B enthaltenen Aufträge entnehmen. So wird der Hauptthread nicht mit Wartereien aufgehalten. Edit: weitere Idee: Die Warteschlangenverwaltung holt immer, wenn eine Änderung passiert (die Warteschlange also sowieso gesperrt ist), den nächsten Auftrag bereits vorsorglich bereit, dann braucht für dessen Abholen nicht gesperrt werden. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:54 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz