2013-04-12 8 views
5

Próbuję przez jakiś czas zrobić "zły pobieranie http" w Delphi, ale TIdHttpCli po prostu nie mogę zrobić, co chcę. Z jakiegoś powodu nie będzie działać w tym samym czasie w wielu wątkach. Proszę spojrzeć prostą demonstracją tego problemu:Naruszenie dostępu z TIdHttp działa na wielu wątkach w tym samym czasie

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; 

David Heffernan EDIT: uproszczony kod w pytaniu. Ten kod nadal manifestuje zachowanie. Moje środowisko testowe to XE3 z Indy dostarczonym z XE3.

+1

@PauloParedes - TThread, zgodnie z sugestią Davida. –

Odpowiedz

8

Masz aplikację wielowątkową. Aby menedżer pamięci działał, aplikacje wielowątkowe muszą ustawić IsMultiThread na True. Stanie się tak, jeśli oprzesz swoje wątki na TThread.

Z documentation:

IsMultiThread jest ustawiona na True, aby wskazać, że menedżer pamięci powinny obsługiwać wiele wątków. IsMultiThread jest ustawione na True przez BeginThread i fabryki klas.

Bo dzwonisz surowy Windows API CreateThread, a nie za pomocą RTL obsługiwane rutyny nici, nic w systemie ustawia IsMultiThread do True. Menedżer pamięci zakłada, że ​​istnieje tylko jeden wątek i nie blokuje dostępu do współużytkowanych struktur danych menedżera pamięci. Stąd problemy, które zauważyłeś.

Jeśli po uruchomieniu ustawisz po prostu IsMultiThread := True, Twój kod będzie działał idealnie. Lub przejdź do używania wątku opartego na TThread.

Pamiętaj, że Twój problem nie ma nic wspólnego z Indy. Możesz zobaczyć ten błąd, po prostu przypisując pamięć sterty w wątku. Ten program umiera za każdym razem w moim systemie:

{$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

Oprócz tego, co zostało powiedziane, chcę tylko zwrócić uwagę, że zarówno kod Paulo, jak i kod Davida, "HttpRequest()" jest błędny. Musi to być funkcja, a nie procedura: 'function HttpRequest (AParam: Pointer): DWORD; stdcall; 'Kiedy nie zgadzasz się z podpisem, może to spowodować wtórne objawy, jeśli nie jesteś ostrożny. –

+0

@David Heffernan, ta idea OP może działać z "" e-mailem z zagniewanym nadawcą "używającym tego samego konta e-mail i wysyłającego do listy odbiorców obecnych w komponencie' Memo'? Lub serwer smtp nie będzie obsługiwał tego samego konta ? (innymi słowy, muszę mieć kilka kont e-mail i dla każdego 1 utworzyć nowy wątek?). – Saulo

Powiązane problemy