Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi Hauptthread splitten und wieder zusammenführen (https://www.delphipraxis.net/152675-hauptthread-splitten-und-wieder-zusammenfuehren.html)

Patrick 1. Jul 2010 14:35

Hauptthread splitten und wieder zusammenführen
 
Hallo,

Ich möchte eine Funktion parallelisieren. Der Code der die Funktion aufruft ist wurscht. Den Code meiner Funktion kann ich spielend parallelisieren. Aber der Code (Aufrufstack), der nach dem Aufruf meiner Funktion bearbeitet wird, ist der Knackpunkt. Ich weis nicht, was danach passiert. Die Funktion wird an X unterschiedlichen Stellen aufgerufen. Erstelle ich einfach nur Subthreads, die meine Aufgabe erfüllen, läuft der Hauptthread weiter und will Ergebnisse ausspucken, die noch gar nicht berechnet wurden. Er solle aber warten, bis meine Subthreads zu ende gerechnet haben. Den Hauptthread kann ich aber nicht so einfach pausieren, da sonst das Programm hängt und die Subthreads keine Synchonizes mehr machen können. Bleiben zwei Möglichkeiten: Ich sage dem Haupttherad er soll an der aktuellen Position Pausieren, aber trotzdem ProcessMessages abarbeiten. Oder ich merke mir irgendwie den Aufrufstack und unterbreche ihn an dieser Stelle.

Code:
     +-----+
     +-----+
-----+?????+-------
|    |      |
|    |      Code nach Funktionsaufruf
|    Funktionsaufruf
Code vor Funktionsaufruf
Sinn des ganzen ist es einfach für die spezielle Funktion alle CPU-Kerne zur Berechnung zu bemühen.

Bummi 1. Jul 2010 14:47

AW: Hauptthread splitten und wieder zusammenführen
 
Einen Counter beim Aufruf hochzählen lassen und OnTerminate dekrementiern und im Programm vor der Weiterverabeitung
While Threadcount>0 do
begin
Application.ProcessMessages;
Sleep(50);
end;
??

Patrick 1. Jul 2010 14:51

AW: Hauptthread splitten und wieder zusammenführen
 
Ja, so was habe ich mir auch schon überlegt, aber ich habe mich gefragt ob es da nicht was eleganteres gibt. Geht das nicht ohne Polling?

sirius 1. Jul 2010 14:58

AW: Hauptthread splitten und wieder zusammenführen
 
Ich würde einen extra thread machen, der alle anderen Threads verwaltet.

Patrick 1. Jul 2010 15:01

AW: Hauptthread splitten und wieder zusammenführen
 
Bliebe doch immer noch das Problem, dass der Hauptthread ungehindert weiter läuft?

sirius 1. Jul 2010 15:02

AW: Hauptthread splitten und wieder zusammenführen
 
soll er ja auch, oder?

himitsu 1. Jul 2010 15:03

AW: Hauptthread splitten und wieder zusammenführen
 
- alle Sub-Threads starten
- warten bis alle Threads beendet sind
- Ergebnisse ausgeben


wie du jetzt wartest ist egal ... da gibt's ja viele Wege
(der Thread bietes z.B. WaitFor)

wenn der Hauptthread auch mal nicht reagieren muß (ala Application.ProcessMessages) die WaitFors aller Thread nacheinander aufrufen (die Reihenfolge ist egal) und wenn man damit durch ist, dann sind alle SubThreads fertig.


PS: es geht auch so
- alle SubThreads starten (je einen Teil abarbeiten lassen)
- der Hautthread kann auch was machen und einen Teil abarbeiten
- warten bis alle Threads beendet sind
- Ergebnisse ausgeben

Patrick 1. Jul 2010 15:19

AW: Hauptthread splitten und wieder zusammenführen
 
@ sirius
Jain. Er darf den Code (Aufrufstack) nach meiner Funktion erst abarbeiten, wenn alle Threads fertig sind. Aber ProcessMessages (Synchronizes, usw...) soll er noch annehmen.

@himitsu
Mit WaitFor blockiere ich doch den Thread, der die Funktion aufruft, ergo den Hauptthread. Ist doch ne Semaphore, oder? Ne Semaphore lässt sich an der Stelle leider nicht verwenden, weil dann auch keine ProcessMessages mehr abgearbeitet werden.

Bummi 1. Jul 2010 15:22

AW: Hauptthread splitten und wieder zusammenführen
 
oder die Aufgabe zerlegen in:

Prepare
lockbi1=1
starte alle Threads
lockbit=0
erstmal fertig

und im OnTerminate:
if lockbit=0 and Threadcount=0 then
2 er Teil Deiner Berechnung

sirius 1. Jul 2010 15:56

AW: Hauptthread splitten und wieder zusammenführen
 
@PAtrick

Der Mainthread macht nur die Programmdarstellung mehr nicht.
Alle anderen Aufgaben werden von einem ControlThread erledigt, inkl. der Aufgaben danach.

blackfin 1. Jul 2010 16:16

AW: Hauptthread splitten und wieder zusammenführen
 
Es gibt ja noch dieses unsägliche (uh, ich trau es mir kaum zu sagen)....goto :duck:

http://delphi.about.com/od/adptips20...goto_label.htm

Ich hab jetzt aber nicht gesagt, dass man es benutzen soll :)
Aber es wäre wohl eine Möglichkeit...wenn auch eine ziemlich gefährliche / unschöne.

Der beste Weg wäre doch aber wohl der, komplett alles Event-gesteuert zu machen, so dass es eben gar nichts gibt, was nach dem Funktionsaufruf "weiterläuft". Wenn alle Threads fertig sind, wird im Hauptthread ein Event gefeuert und dieser zeigt die Berechnungen dann an.
Was spricht denn da dagegen?

himitsu 1. Jul 2010 16:29

AW: Hauptthread splitten und wieder zusammenführen
 
Zitat:

Zitat von Patrick (Beitrag 1032862)
Mit WaitFor blockiere ich doch den Thread, der die Funktion aufruft, ergo den Hauptthread.

Du wolltest doch, daß der Hauptthread warten soll
und das hab ich dann natürlich auch wörtlich genommen :stupid:

mjustin 1. Jul 2010 19:28

AW: Hauptthread splitten und wieder zusammenführen
 
Google mal nach OmniThreadLibrary, die bietet fortgeschrittene Threadfunktionen (Join, Future uvm.) und ist relativ einfach in der Vewendung.

Patrick 2. Jul 2010 10:22

AW: Hauptthread splitten und wieder zusammenführen
 
Okay, stellt such vor, ich habe eine neue "InttoStr" (oder irgend eine andere Funktion, die ihr überall in euren Programmen verwendet) Funktion geschrieben, die durch Multithreading schneller arbeitet. (Und stellt euch vor, die Funktion braucht selbst mit Multithreading 1-2 Sekunden Bearbeitungszeit. Läuft der Hauptthread einfach weiter, ist das Ergebnis noch gar nicht berechnet worden. Bleibt er per Semaphore stehen, steht auch das Programm und es können keine Synchronizes mehr ausgeführt werden.
Ein "Auffang-" Event bringt hier nicht viel. Weil der Aufruf an x beliebigen Stellen im Programm erfolgt, auf den x verschiedene Abläufe folgen. Stellt euch den nachfolgenden Code, als Black-Box vor. Ich gebe euch meine "neue" InttoStr Funktion und ihr könnt die in euren Programmen verwenden, ohne euren Quelltext verändern zu müssen.

Ich habe das Problem jetzt (vorübergehend) mit Polling gelöst.

@mjustin
Danke, werde es mir bei Gelegenheit zu Gemüte führen.

ChrisE 2. Jul 2010 10:54

AW: Hauptthread splitten und wieder zusammenführen
 
Hallo,

ich weiß nicht ob dich das Weiter bringt, oder ob das Performanter ist, aber es ist zumindest mehr OnDemand was das Application.ProcessMessages angeht :-)

Also:
1. Funktion MyIntToStr erzeugt Threads.
2. Es wird in einem Array die gleiche Anzahl an TEvents erzeugt.
3. Thread hat z.B. ein TEvent property. Zuweisung mit den TEventArray.
4. Jeder Thread löst das TEvent aus am ende von seiner Execute-Methode.
5. Funktion MyIntToStr erzeugt sich ein HandleArray aller Events
6. Warten auf das Ende mittels:
Delphi-Quellcode:
doneCount := 0;
doneMax := length(TheHandleArr);
repeat
  Erg := MsgWaitForMultipleObjects(doneMax, @TheHandleArr[0], FALSE, INFINITE, QS_ALLINPUT);
  if (Erg < WAIT_OBJECT_0) or (Erg > WAIT_OBJECT_0 + doneMax -1) then
  begin
    Application.ProcessMessages;
    if Application.Terminated then Exit;
  end else
  begin
    inc(doneCount);
  end;
until doneCount = doneMax
Man könnte hier auch noch zusätzlich ein Abbruch Event hinein bringen. Aber das überlasse ich anderen :-)

Vielleicht hilft es ja.

Greez, Chris

himitsu 2. Jul 2010 10:56

AW: Hauptthread splitten und wieder zusammenführen
 
Mit WaitFor wartet man auf das Ende ... es gibt aber noch andere Möglichkeiten, um rauszubekommen, ob ein Thread schon fertig ist.
(z.B. mit Christians Events)

Wie startets du eigentlich die vielen Threads?

Eventuell kann man da einiges Zusammenfassen und mit in die Klasse einbauen, damit du es überall einfach aufrufen kannst.

Delphi-Quellcode:
X := TMyThread.Create;
Y := TMyThread.Create;
Z := TMyThread.Create;
repeat
  Sleep(10);
  Application.ProcessMessages;
until X.istFertig and Y.istFertig and Z.istFertig;
X.Free;
Y.Free;
Z.Free;
//weiter gehts...
Wenn das Starten einheitlich ist, dann läßt sich alles in eine Start-Funktion des TMyThread verlagen.



Delphi-Quellcode:
class procedure TMyThread.Warte(MyThreads: array of TMyThread);
var b: Boolean;
  i: Integer;
begin
  repeat
    Sleep(10);
    Application.ProcessMessages;
    B := True;
    for i := High(MyThreads) downto 0 do
      if not MyThreads[i].istFertig then
      begin
        B := False;
        Break;
      end;
  until B;
  for i := High(MyThreads) downto 0 do
    MyThreads[i].Free;
end;

SetLength(X, 3);
X[0] := TMyThread.Create;
X[1] := TMyThread.Create;
X[2] := TMyThread.Create;
TMyThread.Warte(X);
Delphi-Quellcode:
class procedure TMyThread.Starte(Parameter...);
var MyThreads: array of TMyThread;
  b: Boolean;
  i: Integer;
begin
  SetLength(MyThreads, 3);
  for i := 0 to High(MyThreads) do
    MyThreads[i] := TMyThread.Create(Parameter...);
  repeat
    Sleep(10);
    Application.ProcessMessages;
    B := True;
    for i := High(MyThreads) downto 0 do
      if not MyThreads[i].istFertig then
      begin
        B := False;
        Break;
      end;
  until B;
  for i := High(MyThreads) downto 0 do
    MyThreads[i].Free;
end;

TMyThread.Starte(Parameter...);

Patrick 2. Jul 2010 11:13

AW: Hauptthread splitten und wieder zusammenführen
 
Hmmm...
Eure Antworten sagen mir, dass ihr auch keine bessere Lösung als Polling kennt. Selbst die Bücher, die ich bisher konsultiert habe schlagen Polling vor. Also ist es Polling.

Meine Umsetzung ist ähnlich eurer. Nur verwende ich den WorkerThreadPool und warte in ner Schleife darauf, dass die PendingJobs bei 0 ankommen.

Danke

himitsu 2. Jul 2010 12:00

AW: Hauptthread splitten und wieder zusammenführen
 
die MsgWaitForMultipleObjects-Variante pollt nicht!
(für eine Beschreibung dieser Variante, ließ dir mal die Infos zum DelayDelay von Hagen durch)

Dann gibt es noch die Möglichkeit, über OnTerminate der Threads sich über deren Ende informieren zu lassen, bzw. ich würde dort die Events für's MsgWaitForMultipleObjects setzen lassen, falls man eigene Events nutzen möchte.

jfheins 2. Jul 2010 13:02

AW: Hauptthread splitten und wieder zusammenführen
 
Zitat:

Zitat von Patrick (Beitrag 1032862)
@ sirius
Jain. Er darf den Code (Aufrufstack) nach meiner Funktion erst abarbeiten, wenn alle Threads fertig sind. Aber ProcessMessages (Synchronizes, usw...) soll er noch annehmen.

Du weist schon dass das ein Widerspruch ist, oder?
Bei der Abarbeitung einer Message soll er einerseits "anhalten und abwarten" und andererseits "andere Nachrichten abarbeiten" ... :roll:

Wenn Multithreading und Parallelisierung so einfach wären, hätte es jeder schon längst gemacht. Aber bei sequentiellen programmiersprachen muss man eben ein bisschen was ändern.

P.S.: ichhab gehört, in Prism geht sowas relativ leicht. Aber auch da muss man vorher nachdenken und man bekommt das ergebnis nicht vor der Rechnung.


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:09 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