![]() |
Definition Funktion um Threads zu befüllen
Guten Abend zusammen,
ich bin gerade dabei, eine multithreaded Anwendung zu schreiben. Dazu erstelle ich eine bestimmte Anzahl an Workerthreads, welche so lange arbeiten, bis es nichts mehr gibt. Jetzt brauche ich aber eine Funktion, die die einzelnen Threads mit Werten versorgt. Doch wo definiere ich diese Funktion? Wenn ich die in der Threadklasse anlege und z.B. 5 Threads anlege, dann gibt es natürlich diese Methode auch 5 mal und jeder Thread würde alles abarbeiten. Daher überlege ich, diese Funktion in der TForm Klasse zu definieren. Doch dann müsste ich aus den Threads raus die Funktion so aufrufen: MeinWert := TForm1.MeineFunktion; Doch macht man das so oder gibt es da nicht eine bessere Lösung? |
AW: Definition Funktion um Threads zu befüllen
Du hast doch XE4 und dort hast du auch die anonymen Methoden
Schreibe einfach eine anonyme Methode und reiche die an den ThreadPool. Der gibt diese dann an einen freien Worker und der führt diese dann aus. Wenn du diese anonyme Methode jetzt noch in ein (oder eher 2) Interface bettest, dann wird alles schön :) |
AW: Definition Funktion um Threads zu befüllen
Mir fällt da gerade ein, die Threadklasse hat doch auch die Synchronize Methode.
Das würde mir ja eigentlich schon reichen. Nur scheint man damit keine anonyme Funktionen aufrufen zu können.
Delphi-Quellcode:
MeinString := TThread1.Synchronize(
function : String begin result := 'Nur ein Test'; end ); |
AW: Definition Funktion um Threads zu befüllen
Lies mal die Hilfe zu TThread.Synchronize(). Was du vor hast, macht man in der Regel mit CriticalSections, und wessen Member die versorgende Methode letztlich ist, hängt davon nicht ab. CriticalSections stellen sicher, dass zwei Threads (in deinem Fall Mainthread und dein Workerthread) Code nicht gleichzeitig ausführen können, der zwischen dem Einstieg und dem Ausstieg aus der CriticalSection steht. Genutzt wird soetwas zum Beispiel, wenn ein Thread eine Liste eines anderen befüllt. Sowohl der schreibende als auch der lesende Zugriff müssen dabei dann gegeneinander verriegelt werden. Pseudocode:
Delphi-Quellcode:
// Workerthread
procedure TWorkerThread.Execute; begin while not Terminated do begin if not List.IsEmpty then begin MyCriticalSection.Enter; try DoSomethingWith(List[0]); List.Delete(0); finally MyCriticalSection.Leave; end; end; end; end; procedure TWorkerThread.AddListItem(aListItem: TListItem); begin MyCriticalSection.Enter; try List.Add(aListItem); finally MyCriticalSection.Leave; end; end; // Hauptthread procedure TForm1.OnButton1Click(Sender: TObject); begin WorkerThread.AddListItem(TListItem.Create(foo, bar)); end; |
AW: Definition Funktion um Threads zu befüllen
Zitat:
Denn man kann nur parameterlose und vorallem rückgabewertlose vordefinierte Synchronize-Methoden ausrufen, so wie das schon immer war. Und man muß natürlich auch beachten was man alles als Parameter übergeben muß.
Delphi-Quellcode:
TThread.Synchronize(nil, procedure
begin MeinString := 'Nur ein Test'; end); TThread.Synchronize(Thread1, procedure begin MeinString := 'Nur ein Test'; end); {T}Thread1.Synchronize(procedure begin MeinString := 'Nur ein Test'; end); ... @Medium: Natürlich müsste doch jeder Zugriff auf List in die CS rein, also auch das
Delphi-Quellcode:
.
if not List.IsEmpty then
Und bezüglich der sinnlosen CPU-Auslastung könnte/sollte man das Ganze noch um Events erweitern. |
AW: Definition Funktion um Threads zu befüllen
Das ist eine Illustration, eine Skizze. Deswegen ja Pseudocode. Bei dem IsEmpty hast du allerdings Recht, der ist mir durch die Lappen gegangen. (Generell wäre es an sich geschickter eine Threadsafe-Liste von TList o.ä. abzuleiten und dort die Criticalsection unterzubringen, sowie alle Zugriffsmethoden dahingehend zu erweitern. Aber das wäre hier doch etwas lang geworden.) Und statt Events tut's in so einfachen Fällen auch ein Sleep(1) in der Schleife. Nicht Best-Practice, aber ich habe noch keine wirklich gute technische Gegenargumente dazu gesehen.
|
AW: Definition Funktion um Threads zu befüllen
Natürlich nur eine Skizze, trotzdem kann man verbessern:
Zitat:
Delphi-Quellcode:
Jetzt ist nur das Extrahieren des ersten Elements der Jobliste exklusiv. 'DoSomethingWith' sollte nun noch prüfen, ob der übergebene Job <> nil ist.
// Workerthread
procedure TWorkerThread.Execute; Function NextItemInList : ISomethingToDo; begin MyCriticalSection.Enter; try If List.Count>0 then begin Result := List[0]; List.Delete(0); else Result := nil; finally MyCriticalSection.Leave; end; end; begin ... DoSomethingWith(NextItemInList); ... Ich würde zudem noch eine Semaphore einführen und den Thread schlafen legen. Das 'AddItem' weckt ihn auf, indem die Semaphore per 'ReleaseSemaphore' um 1 erhöht wird. Damit rennt die Execute-Methode automatisch so lange, wie Jobs in der Liste sind. Siehe auch: ![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:40 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 by Thomas Breitkreuz