2013-01-25 15 views
5

ich dabei bin 10.Migration von Indy 9 bis 10 mit Delphi, TIdSchedulerOfThreadPool Initialisierung

eine Delphi-App von Indy 9 bis Indy aktualisieren Es ist sehr schmerzhaft, wie scheinbar viel geändert hat.

Ich bin auf einem Schritt fest. Hier

ist der alte Code (Arbeit mit Indy 9):

Ein Thread-Pool erstellt und jeder Thread des Pools wird initialisiert und dann gestartet. Die einzelnen Threads erstellen einen Indy-HTTP-Client (aber das spielt hier keine Rolle).

TUrlThread = class(TIdThread) 

... 

var 
    i: Integer; 
begin 
    // create the Pool and init it 
    Pool   := TIdThreadMgrPool.Create(nil); 
    Pool.PoolSize := Options.RunningThreads; 
    Pool.ThreadClass:= TUrlThread; 

    // init threads and start them 
    for i := 1 to Options.RunningThreads do 
    begin 
    with (Pool.GetThread as TUrlThread) do 
    begin 
     Index  := i; 
     Controler := Self; 
     Priority := Options.Priority; 
     Start; 
    end; 
    end; 

Die TIdThreadMgrPool Klasse ist mit Indy 10.

Ich habe für einen Ersatz und TIdSchedulerOfThreadPool sah weg wie ein Sieger aussieht, aber ich kann es nicht laufen bekommen.

Hier ist die modifizierte (Indy 10) Code:

TUrlThread = class(TIdThreadWithTask) 

... 

var 
    i: Integer; 
begin 
    // create the Pool and init it 
    Pool   := TIdSchedulerOfThreadPool.Create(nil); 
    Pool.PoolSize := Options.RunningThreads; 
    Pool.ThreadClass:= TUrlThread; 

    // init threads and start them 
    for i := 1 to Options.RunningThreads do 
    begin 
    with (Pool.NewThread as TUrlThread) do 
    begin 
     Index  := i; 
     Controler := Self; 
     Priority := Options.Priority; 
     Start; 
    end; 
    end; 

ich hier eine Zugriffsverletzung Ausnahme erhalten (dies ist indy-Code):

procedure TIdTask.DoBeforeRun; 
begin 
    FBeforeRunDone := True; 
    BeforeRun; 
end; 

FBeforeRunDone ist gleich Null.

Antwort

7

Sie haben Recht, dass TIdSchedulerOfThreadPool der Indy 10 Ersatz für TIdThreadMgrPool ist. Was Sie jedoch nicht berücksichtigen, ist, dass die TIdScheduler Architektur ein wenig anders ist als die TIdThreadMgr Architektur.

In Indy 10, TIdThreadWithTask funktioniert nicht von selbst. Wie der Name andeutet, führt TIdThreadWithTask einen Task aus, der ein TIdTask-abgeleitetes Objekt ist (wie TIdContext, das Indy 10 ersetzt für TIdPeerThread), das mit dem Thread verknüpft wird. Sie führen Threads aus, ohne ihnen Aufgaben zu geben, weshalb Sie abstürzen. Um Start() manuell aufzurufen, müssen Sie zuerst ein TIdTask -basiertes Objekt erstellen und der TIdThreadWithTask.Task-Eigenschaft zuweisen. TIdTCPServer Griffe dass TIdScheduler.AcquireYarn() durch den Aufruf eines TIdYarn-Objekt zu erstellen, die zu einem TIdThreadWithTask Objekt verknüpft ist, erstellt dann ein TIdContext Objekt und übergibt sie an TIdScheduler.StartYarn(), die die TIdYarn verwendet die TIdThreadWithTask zuzugreifen seine Task Eigenschaft zuweisen, bevor dann Start() auf sie anrufen.

Aber alles ist nicht verloren. Sowohl in Indy 9 als auch in 10 sollten Sie wirklich nicht TIdThread.Start() manuell aufrufen, um damit zu beginnen. TIdTCPServer behandelt dies nach dem Akzeptieren einer neuen Clientverbindung, beim Abrufen eines Threads von dessen ThreadMgr/Scheduler und beim Zuordnen der Clientverbindung zum Thread. Sie können Ihre Thread-Eigenschaften nach Bedarf initialisieren, ohne die Threads sofort auszuführen. Die Eigenschaften werden wirksam, wenn die Threads das erste Mal zu einem späteren Zeitpunkt ausgeführt werden.

starten:

TUrlThread = class(TIdThread) 

... 

var 
    i: Integer; 
begin 
    // create the Pool and init it 
    Pool   := TIdThreadMgrPool.Create(nil); 
    Pool.PoolSize := Options.RunningThreads; 
    Pool.ThreadClass:= TUrlThread; 
    Pool.ThreadPriority := Options.Priority; 

    // init threads and start them 
    for i := 1 to Options.RunningThreads do 
    begin 
    with (Pool.GetThread as TUrlThread) do 
    begin 
     Index  := i; 
     Controler := Self; 
    end; 
    end; 

.

TUrlThread = class(TIdThreadWithTask) 

... 

var 
    i: Integer; 
begin 
    // create the Pool and init it 
    Pool   := TIdSchedulerOfThreadPool.Create(nil); 
    Pool.PoolSize := Options.RunningThreads; 
    Pool.ThreadClass:= TUrlThread; 
    Pool.ThreadPriority := Options.Priority; 

    // init threads and start them 
    for i := 1 to Options.RunningThreads do 
    begin 
    with (Pool.NewThread as TUrlThread) do 
    begin 
     Index  := i; 
     Controler := Self; 
    end; 
    end; 

Nun, mit diesem gesagt, eine letzte Sache aufpassen. In Indy 9 und 10 ist es möglich, dass Threads nach Abschluss des Initialisierungscodes nicht mehr in den Pool zurückgesetzt werden und dass neue Threads zum Pool hinzugefügt werden. Die PoolSize ist die minimale Anzahl der Threads im Pool, nicht eine absolute Anzahl. Mehr als PoolSize Anzahl der Clients kann eine Verbindung mit dem Server herstellen, und es wird erfreulicherweise mehr Threads für sie zum Zeitpunkt ihrer Verwendung erstellen und damit Ihren Initialisierungscode umgehen. In beiden Versionen ist der beste Ort zum Initialisieren der Threads der TUrlThread-Konstruktor. Speichern Sie Ihren Zeiger Controler irgendwo, dass der Konstruktor es bei Bedarf erreichen kann. Und es ist nicht sinnvoll, jedem Thread einen Index zuzuweisen, da sich die Reihenfolge der Threads im Pool dynamisch im Laufe der Zeit ändert.

Tatsächlich ist Ihr manueller Initialisierungscode tatsächlich in beiden Versionen aus einem anderen Grund der falsche Ansatz. Sowohl TIdThreadMgrPool.GetThread() als auch TIdSchedulerOfThreadPool.NewThread() fügen den neuen Thread dem Pool überhaupt nicht hinzu. Threads werden dem Pool in Indy 9 und 10 hinzugefügt, wenn ein Thread aufhört zu laufen, und es genügend Platz gibt, den Thread zur Wiederverwendung zu speichern, und zusätzlich in Indy 10 nur, wenn TIdTCPServer gestartet wird. Sie erstellen also tatsächlich Threads, die gar nichts tun und nicht vom Pool verfolgt werden. Umso mehr Grund, Ihren Initialisierungscode in beiden Versionen neu zu entwerfen, damit sich Threads initialisieren, wenn sie unter normalen Bedingungen erstellt werden, anstatt sich in die Architektur zu hacken, um sie manuell zu erstellen.