2013-04-12 58 views
5

我想了很長時間在德爾福做一個「憤怒的http下載器」,但TIdHttpCli只是不能做我想做的。出於某種原因,它不會在許多線程中同時運行。請看看一個這個問題的簡單的例子:訪問衝突TIdHttp同時在多個線程上運行

procedure HttpRequest(AParam : Integer); stdcall; 
var 
    lHttp: TIdHttp; 
begin 
    lHttp := TIdHttp.Create(nil); 
    { 
    lHttp.Get(
    'http://stackoverflow.com/questions/15977505/', 
    TMemoryStream.Create 
); 
    } 
end; 

procedure TForm1.FormCreate(Sender: TObject); 
var 
    i: Integer; 
    tid: DWORD; 
begin 
    for i := 0 to 4 do 
    CreateThread(nil, 0, @HttpRequest, nil, 0, tid); 
end; 

大衛·赫弗南編輯:我在簡化問題的代碼。該代碼仍然表現出這種行爲。我的測試環境是XE3,與XE3一起交付的Indy。

+1

@PauloParedes - TThread,如David所建議的。 –

回答

8

您有一個多線程應用程序。爲了使內存管理器工作,多線程應用程序必須將IsMultiThread設置爲True。如果你的線程基於TThread,將會發生這種情況。

documentation

IsMultiThread設置爲True,表明內存管理器應該支持多線程。由BeginThread和類工廠將IsMultiThread設置爲True。

因爲您呼叫的原始的Windows API CreateThread,而不是使用RTL支持線程程序,沒有在系統設置IsMultiThreadTrue。所以內存管理器假定只有一個線程,並且不鎖定對內存管理器的共享數據結構的訪問。因此你觀察到的問題。

如果您在啓動時簡單設置IsMultiThread := True,您的代碼將完美工作。或切換到使用基於TThread的線程。

請注意,您的問題與Indy完全沒有關係。你可以簡單地通過在線程中分配堆內存來看到這個失敗。該程序每次都在我的系統上死亡:

{$APPTYPE CONSOLE} 

uses 
    SysUtils, Windows; 

function HttpRequest(AParam : Integer): DWORD; stdcall; 
var 
    i: Integer; 
    P: Pointer; 
begin 
    Result := 0; 
    for i := 1 to 100000 do 
    GetMem(P, 1); 
end; 

var 
    i: Integer; 
    tid: DWORD; 

begin 
    try 
    //IsMultiThread := True;//include this line to make program correct 
    for i := 0 to 15 do 
     CreateThread(nil, 0, @HttpRequest, nil, 0, tid); 
    except 
    on E:Exception do 
     Writeln(E.Message); 
    end; 
    Readln; 
end. 
+3

除了已經說過的話,我只想指出,在Paulo的代碼和David的代碼中,「HttpRequest()」被聲明爲錯誤的。它需要是一個函數,而不是一個過程:'函數HttpRequest(AParam:指針):DWORD; stdcall;'當您簽名不匹配時,如果您不小心,可能會導致繼發症狀。 –

+0

@David Heffernan,這個OP的想法可以使用一個「」憤怒的發件人電子郵件「使用相同的電子郵件帳戶併發送到一個」備忘錄「組件中的收件人列表?或SMTP服務器不會支持它具有相同的帳戶?(換句話說,我必須有幾個電子郵件帳戶,每個帳戶創建一個新的線程?)。 – Saulo