2013-01-25 29 views
5

我在更新,從印第安納波利斯9 Delphi應用程序到印第安納波利斯10從印第安納波利斯9遷移到10德爾福,TIdSchedulerOfThreadPool初始化

這是很痛苦的過程,顯然發生了很多變化。

我被困在一個步驟。

這裏是舊代碼(有工作的Indy 9):

創建一個線程池,池中的每個線程進行初始化,然後啓動。 單個線程創建一個indy http客戶端(但這裏沒關係)。

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; 

TIdThreadMgrPool類曠古印10

我已經找了一個替代和TIdSchedulerOfThreadPool看起來像一個勝利者, 但我不能讓它運行。

下面是修改(印第安納波利斯10)代碼:

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; 

我這裏得到一個訪問衝突異常(這是印碼):

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

FBeforeRunDone爲零。

回答

7

你是對的TIdSchedulerOfThreadPool是Indy 10的替代TIdThreadMgrPool。但是,您沒有考慮到的是TIdScheduler體系結構與TIdThreadMgr體系結構有很大不同。

在Indy 10中,TIdThreadWithTask不能自行操作。顧名思義,TIdThreadWithTask執行任務,這是TIdTask衍生的對象(例如TIdContext,它是Indy 10的替換爲TIdPeerThread),它與該線程相關聯。您正在運行線程而不給他們執行任務,這就是您遇到崩潰的原因。爲了手動撥打Start(),您需要先創建一個基於TIdTask的對象並將其分配給TIdThreadWithTask.Task屬性。 TIdTCPServer處理通過調用TIdScheduler.AcquireYarn()創建鏈接到一個TIdThreadWithTask對象TIdYarn對象,然後創建一個TIdContext對象,並把它傳遞給TIdScheduler.StartYarn(),它使用TIdYarn訪問TIdThreadWithTask然後調用它Start()之前,其Task屬性分配。

但是,一切都不會丟失。在Indy 9和10中,你都不應該手動撥打TIdThread.Start()開始。 TIdTCPServer會在接受新的客戶端連接後處理它,從其ThreadMgr/Scheduler獲取線程,並將客戶端連接關聯到該線程。您可以根據需要初始化您的線程屬性,而無需實際立即運行線程。這些屬性將在線程第一次開始運行時生效。

試試這個:

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; 

現在,有了這個說法,最後要注意的一件事。在Indy 9和10中,完成後可能不會將線程放回池中,並且在初始化代碼運行後將新線程添加到池中。 PoolSize是保留在池中的最小線程數,而不是絕對計數。超過PoolSize的客戶端數量可以連接到服務器,並且它會在需要時爲它們愉快地創建更多線程,從而繞過您的初始化代碼。在這兩個版本中,創建線程的最佳位置在TUrlThread構造函數中。將您的Controler指針存儲在構造函數可以在需要時訪問它的地方。因爲池中線程的順序隨時間動態變化,所以將Index分配給每個線程是沒有意義的。

實際上,由於其他原因,您的手動初始化代碼實際上是兩個版本中的錯誤代碼。 TIdThreadMgrPool.GetThread()TIdSchedulerOfThreadPool.NewThread()都不會將新線程添加到池中。當線程停止運行時,線程將添加到Indy 9和10中的池中,並且有餘地保存線程以供重用,並且僅在TIdTCPServer啓動時纔在Indy 10中使用線程。所以你實際上正在創建實際上沒有做任何事情的線程,並且不被池中的任何人跟蹤。更有理由在兩個版本中重新設計初始化代碼,以便線程在正常情況下創建它們時自行初始化,而不是在黑客入侵體系結構以手動創建它們。