Reputation: 663
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
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
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