2013-10-04 3 views
7

Ich las die Antwort auf another question here über die Notwendigkeit, Coinitialize und Couninitialize zu ADO-Objekten zu verbinden. Ich muss etwas ähnliches tun, um Soap-Aufrufe in einem Thread durchzuführen.Threaded Initialisierung und Bereinigung in Delphi

Gibt es eine Möglichkeit, ein TThread-Objekt zu überschreiben, damit etwas automatisch vor und nach innerhalb des Threads ausgeführt wird?

Für dieses Beispiel konvertieren wir in ein SOAP-Backend und müssen eine Menge davon tun, und es würde ein wenig Zeit sparen, ein neues SOAP-freundliches TThread zu überschreiben, als coinitialize und couninitialze zu jedem Thread hinzuzufügen. Aber im Allgemeinen scheint das Initialisieren von und das Aufräumen des Threads innerhalb des Threads manchmal wie eine gute Idee. Im Moment scheint es, als könntest du nur das eine oder das andere tun.

+0

Mit anderen Worten, ja. Peter, was sind deine Bedenken, dies zu tun? –

Antwort

7

Vielleicht möchten Sie etwas wie folgt aus:

type 
    TMyThread = class sealed(TThread) 
    private 
    FOnBeforeExecute: TProc; 
    FOnExecute: TProc; 
    FOnAfterExecute: TProc; 
    protected 
    procedure Execute; override; 
    public 
    property OnBeforeExecute: TProc read FOnBeforeExecute write FOnBeforeExecute; 
    property OnExecute: TProc read FOnExecute write FOnExecute; 
    property OnAfterExecute: TProc read FOnAfterExecute write FOnAfterExecute; 
    end; 

procedure TMyThread.Execute; 
begin 
    if Assigned(OnBeforeExecute) then 
    OnBeforeExecute; 
    try 
    if Assigned(OnExecute) then 
     OnExecute; 
    finally 
    if Assigned(OnAfterExecute) then 
     OnAfterExecute; 
    end; 
end; 

ich es eine versiegelte Klasse gemacht, so dass Sie nicht Execute mit etwas ersetzen kann, die das Design bricht. Der zusätzliche Vorteil besteht darin, dass Sie die Thread-Prozedur mithilfe von Ereignissen von der implementierenden Klasse entkoppeln können.

+0

Das ist cool, die entkoppelten Methoden sind die Art, wie die meisten unserer Threads bereits funktionieren, aber das ist ein bisschen eleganter. Vielen Dank! –

+0

Warum in der Welt brauchen Sie Veranstaltungen dafür? Machen Sie einfach eine virtuelle Methode wie 'ExecuteContext' aus dem' CoInitialize, CoUninitialize'-Paar und überschreiben Sie diesen 'ExecuteContext' in Ihren Nachkommen. Ich mag das überhaupt nicht. – TLama

+0

'TMyBaseThread' und' versiegelt' in einer Zeile liest sich seltsam für mich ... vielleicht den Namen ändern? – jpfollenius

5

Wenn Sie eine spezielle Initialisierung und Finalisierung mit Ereignissen wie in Davids Antwort durchführen möchten, müssen Sie diese Ereignisse für jeden von Ihnen erstellten Thread zuweisen. Und das bedeutet, dass entweder ein bestimmter Konstruktor hinzugefügt wird, um sie zu übergeben oder die Threads im gesperrten Modus zu erstellen.

Persönlich kann ich nicht wirklich, wie all diese Dinge, die daran erinnern, zu tun und deshalb für eine polymorphe Lösung gehen würde:

type 
    TInitializeFinalizeThread = class(TThread) 
    protected 
    procedure InitializeExecution; virtual; 
    procedure FinalizeExecution; virtual; 
    procedure InternalExecute; virtual; 
    procedure Execute; override; 
    end; 

procedure TInitializeFinalizeThread.Execute; 
begin 
    InitializeExecution; 
    try 
    InternalExecute; 
    finally 
    FinalizeExecution; 
    end; 
end; 

Themen benötigen Ole Stuff zu tun, dann eine gemeinsame Basis haben könnte das braucht Pflege der Initialisierung und finialization:

type 
    TOleThread = class(TInitializeFinalizeThread) 
    protected 
    procedure InitializeExecution; override; 
    procedure FinalizeExecution; override; 
    end; 

procedure TOleThread.InitializeExecution; 
begin 
    CoInitialize; 
end; 

procedure TOleThread.FinalizeExecution; 
begin 
    CoUninitialize; 
end; 

das bedeutet, dass Klassen, die tatsächlich etwas tun wird sind gerade von TOleThread erben können und dass die Initialisierung und Finalisierung getroffen wurden betreut, so dass sie sicher sein, nur müssen InternalExecute überschreiben.

type 
    TWordMailMergeThread = class(TInitializeFinalizeThread) 
    protected 
    procedure InternalExecute; override; 
    end; 

procedure TWordMailMergeThread.InternalExecute; 
begin 
    // Whatever you need this to do. 
end; 

Obwohl sie natürlich frei, die InitializeExecution und FinalizeExecution Methoden außer Kraft zu setzen einzurichten und beenden Sie die Verbindung zum OLEServer (Word in diesem Beispiel), anstatt es in den InternalExecute tun.

+0

Soll der InternalExecute auch als abstrakt deklariert werden, um einen Compiler-Hinweis darüber zu haben, was implementiert werden soll? –

+0

@ J.Gonzalez: Ja, muss nicht, aber es kann helfen. Wie viel hängt von dem Vererbungsbaum (Tiefe) ab, den Sie anstreben. Bedenken Sie jedoch, dass der Compiler nur explizite Typinstanziierungen abfangen kann. Wenn Sie eine Klasse über Metaklassen instanziieren ('TOleThreadClass = Klasse von TOleThread;'), erhalten Sie keine Compiler-Hilfe, aber Laufzeitausnahmen. –