Es gibt Fremd-Bibliotheken, die sowas drin haben.
Das Ganze kann man ja noch mit vielen Dingen erweitern und somit nicht allen Recht machen ... den Einen isses zuviel und Anderen fehlt immer irgendwas.
* z.B. ein Pooling, damit man 200 Dateien downloaden kann, aber nicht zu viele Threads gleichzeitig laufen.
* schönere Fehlernehandlung
* Proxy
* uvm.
Je nach Anforderung muß man sich dann was Passendes suchen.
Es gibt verschiedene Arten von Prozeduren/Methoden
und genauso gibt es verschiedene Arten von MethodenZeigern, welche Referenzen auf diese Methoden aufnehmen können.
Delphi-Quellcode:
type
TEvent1 = reference
to procedure(
const URL:
String; Stream: TStream; Error:
Exception);
// Proc1, Proc2, Proc3, Proc4 und Inline5
TEvent2 =
procedure(
const URL:
String; Stream: TStream; Error:
Exception)
of object;
// Proc2, Proc3
TEvent3 =
procedure(
const URL:
String; Stream: TStream; Error:
Exception);
// Proc1 (glaub auch Proc4)
// Prozedur
procedure Proc1(
const URL:
String; Stream: TStream; Error:
Exception);
type
TDemo =
class
// Methode
procedure Proc2(
const URL:
String; Stream: TStream; Error:
Exception);
// KlassenMethode
class procedure Proc3(
const URL:
String; Stream: TStream; Error:
Exception);
// statische KlassenMethode
class procedure Proc4(
const URL:
String; Stream: TStream; Error:
Exception);
static;
end;
// anonyme Methode, also "Inline5" im Code
begin
eineVariable :=
procedure(
const URL:
String; Stream: TStream; Error:
Exception)
begin
end;
AlsParameter(
procedure(
const URL:
String; Stream: TStream; Error:
Exception)
begin
end);
end;
// eingebettete Prozedur
procedure {TDemo.}Test;
procedure Proc6(
const URL:
String; Stream: TStream; Error:
Exception);
begin
end;
begin
Proc6(…);
end;
Freigeben muß man den Thread ja nicht selbst, denn durch das FreeOnTerminate gibt er sich selbst frei.
Weil man extern nicht weiß wann, darf extern grundsätzlich niemals "ungeschützt" auf eine Variable zugegriffen werden, welche auf diesen Thread zeigt.
Extern garkeine Variable, mit dem Objektzeiger, und schon kommt auch niemand auf dumme Ideen.
Ohne FreeOnTerminate könnte man extern z.B. auf Thread.Terminated prüfen
und anschließend selbst den den Thread freigeben, bzw. vorher z.B. die runtergeladenen Daten von ihm abholen.
Man kann selbst TThread ableiten
und seinen Code ins Execute einfügen, sowie eventuell auch ins Create.
Im Prnzip gibt es aber bereits eine fertige Ableitung des TThread,
die eine Prozedur bekommt, welche sie dann im Thread ausführt.
TThread.CreateAnonymousThread
Delphi-Quellcode:
type
TAnonymousThread = class(TThread)
private
FProc: TProc;
protected
procedure Execute; override;
public
constructor Create(const AProc: TProc);
end;
class function TThread.CreateAnonymousThread(const ThreadProc: TProc): TThread;
begin
Result := TAnonymousThread.Create(ThreadProc);
end;
constructor TAnonymousThread.Create(const AProc: TProc);
begin
inherited Create(True);
FreeOnTerminate := True;
FProc := AProc;
end;
procedure TAnonymousThread.Execute;
begin
FProc();
end;
Also anstatt einer eigenen TThread-Klasse, hatte ich einfach nur dieses Fertige benutzt.
- Die Aktionen zum Erstellen kann man ja vor oder im Create erledigen.
- Und das für's Execute wurde hier einfach als Methode/Event reingegeben, anstatt es direkt reinzuschreiben.
Ohne den auskommentierten Code, für eine alternative Behandlung, ist es hier recht kurz gehalten (passt alles komplett auf den Bildschirm),
und durch die anonymen (eingebetteten) Methoden liegt hier der Code funktional übersichtlich in seiner Ablaufreihenfolge.
Aber grundsätzlich ist es auch kein Problem Vieles in externe Methoden auszulagern, aber dann am Besten schön in einer Klasse gekapselt.
Bei dem eingebetteten Synchronize kann man es auch ausnutzen, dass sich Variablen "automatisch" vom Übergeordneten Code dort reingeben lässt.
(Delphi verschiebt diese Variablen "heimlich" in ein Interface, mit Referenzzähung ... bis der aufrufende Code und der Eingebetette alle beendet wurden)