Hasan Manzak
Hasan Manzak

Reputation: 663

What is the proper way to pass a ThreadFunction to CreateThread API

Definitions first:

uses
  Windows;

type
  TThreadParams = record
    FParam1 : Integer;
    FParam2 : array [0..511] of Byte;
  end;

  TFoo = class
  private
    FThreadHandle: THandle;
    FThreadID : Cardinal;
    FSomeParameters: TThreadParams;

    function procInObject(const Params: Pointer): DWord; stdcall;
  public
    procedure CreateObjThread;
  end;

function procInInterface(const Params: Pointer): DWord; stdcall;

implementation

function procInInterface(const Params: Pointer): DWord;
begin
  Result := High(Cardinal);

  while True do
  begin
    //Do something with Params
  end;
end;

{ TFoo }

procedure TFoo.CreateObjThread;
begin
  FThreadHandle := CreateThread(nil, 0, @procInInterface, @FSomeParameters, CREATE_SUSPENDED, FThreadID);

  //FThreadHandle := CreateThread(nil, 0, @procInObject, Self, CREATE_SUSPENDED, FThreadID);
end;

function TFoo.procInObject(const Params: Pointer): DWord;
begin
  Result := High(Cardinal);

  while True do
  begin
    //Do something with Params
  end;
end;

Now, as you can see I'm trying to create an anonymous thread with WinAPI. I don't want to use TThread class or some libraries like Omni.

The problem is when I do

procedure TFoo.CreateObjThread;
begin
  FThreadHandle := CreateThread(nil, 0, @procInInterface, @FSomeParameters, CREATE_SUSPENDED, FThreadID);

  //FThreadHandle := CreateThread(nil, 0, @procInObject, Self, CREATE_SUSPENDED, FThreadID);
end;

code compiles and when I do

procedure TFoo.CreateObjThread;
begin
  //FThreadHandle := CreateThread(nil, 0, @procInInterface, @FSomeParameters, CREATE_SUSPENDED, FThreadID);

  FThreadHandle := CreateThread(nil, 0, @procInObject, Self, CREATE_SUSPENDED, FThreadID);
end;

it doesn't. Compiler says "[DCC Error] Unit1.pas(45): E2036 Variable required". So a question arises; Do I have to use some methods declared in Unit interface rather than a class of an object, in order to achive what I want? What are the catches those make procInInterface a variable and procInObject doesn't?

On the other hand it was able to compile

procedure TFoo.CreateObjThread;
begin    
  FThreadHandle := CreateThread(nil, 0, @TFoo.procInObject, Self, CREATE_SUSPENDED, FThreadID);
end;

but this seems inappropriate to me. Does this way causes to all instances of TFoo using same code block for procInObject rather then having their own code block? Where am I wrong?

Upvotes: 1

Views: 465

Answers (2)

David Heffernan
David Heffernan

Reputation: 612954

You cannot pass an instance method because it is the wrong type. Your attempts to use procInObject can never work.

A thread procedure is a plain flat procedure that is not a method of a class. In order to get the instance into your thread you need to pass it using the Params arguments.

The thread function looks like this:

function ThreadProc(Params: Pointer): DWORD; stdcall;
var
  Obj: TFoo;
begin
  Obj := TFoo(Params);
  ....
end;

The procedure can now call methods on Obj.

The call to CreateThread:

procedure TFoo.CreateObjThread;
begin    
  FThreadHandle := CreateThread(nil, 0, @ThreadProc, Self, CREATE_SUSPENDED, FThreadID);
end;

Upvotes: 2

Martin James
Martin James

Reputation: 24857

You are wrong in thinking that it is inappropriate, or wrong, for multiple threads to run the same code block. That is absolutely fine and is often done. Code, (unless self-modifying) is intrisically thread-safe.

Not sure why you need a separate record/class for the thread params, rather than simply using fields of TFoo, but I guess it's your design:).

Cast the parameter in 'ProcInInterface' back to a TFoo and you should be OK.

You probably realize that you need to be careful about freeing TFoo, either ensuring that the thread is terminated, (maybe in its d'tor), or never explicitly freeing it and allowing the OS to terminate it at app close.

What do you have against the TThread class, (apart from the horrible synchronize/WaitFor/OnTerminate that you do not have to use)?

Upvotes: 2

Related Questions