Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access Violation with TIdHttp running on many threads at same time

I'm trying for quite some time to do a "angry http downloader" in delphi, but TIdHttpCli just cant do what I want. For some reason it won't run at the same time in many threads. Please take a look a the simple demonstration of this problem:

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: I simplified the code in the question. This code still manifests the behaviour. My test environment was XE3 with the Indy that was delivered with XE3.

like image 320
user2092868 Avatar asked Apr 12 '13 17:04

user2092868


People also ask

Is it possible to have multiple threads on a tidhttp object?

multiple threads, but each thread must have its OWN TidHTTP object. that his won't work. have to make sure, that only one thread at a time has access to this memory. finished. This can be done with synchronize, but I guess that is not what

How do I execute a ttestthread?

procedure TTestThread.Execute; create/destroy the object there. then it will start executing immedieatly. The only thing that a thread does, is to run the Execute procedure once. and make sure that everything that the thread accesses is safe. That should help for a start. Ok, I need a more complete example.. I want to put the GET and POST

What does a thread actually do?

The only thing that a thread does, is to run the Execute procedure once. and make sure that everything that the thread accesses is safe. That should help for a start. Ok, I need a more complete example..


1 Answers

You have a multi threaded application. In order for the memory manager to work, multi-threaded applications must set IsMultiThread to True. This will happen if you base your threads on TThread.

From the documentation:

IsMultiThread is set to True to indicate that the memory manager should support multiple threads. IsMultiThread is set to True by BeginThread and class factories.

Because you are calling the raw Windows API CreateThread, and not using the RTL supported thread routines, nothing in the system sets IsMultiThread to True. And so the memory manager assumes that there is only a single thread, and does not lock access to the memory manager's shared data structures. Hence the problems you observed.

If you simply set IsMultiThread := True at startup, your code will work perfectly. Or switch to using a TThread based thread.

Note that your issue has nothing at all to do with Indy. You can see this failure simply by allocating heap memory in the thread. This program dies every time on my system:

{$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.
like image 79
David Heffernan Avatar answered Oct 11 '22 06:10

David Heffernan