将ThreadFunction传递给CreateThread API的正确方法是什么

时间:2014-02-07 12:45:01

标签: multithreading delphi winapi

第一个定义:

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;

现在,正如您所看到的,我正在尝试使用WinAPI创建一个匿名线程。我不想使用TThread类或像Omni这样的库。

问题出在我做的时候

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

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

代码编译,当我做

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

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

它没有。编译器说“[DCC错误] Unit1.pas(45):E2036需要变量”。所以出现了一个问题;我是否必须使用在Unit接口中声明的一些方法而不是一个对象的类,以便实现我想要的东西?那些使 procInInterface 变量而 procInObject 没有的捕获量是什么?

另一方面,它能够编译

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

但这对我来说似乎不合适。这种方式是否会导致TFoo的所有实例使用 procInObject 的相同代码块,而不是拥有自己的代码块?我哪里错了?

2 个答案:

答案 0 :(得分:2)

您认为多个线程运行相同的代码块是不合适或错误的,这是错误的。这绝对没问题,经常做。代码(除非自我修改)本质上是线程安全的。

不确定为什么你需要一个单独的记录/类用于线程参数,而不是简单地使用TFoo的字段,但我想这是你的设计:)。

将'ProcInInterface'中的参数强制转换回TFoo,你应该没问题。

你可能意识到你需要注意释放TFoo,要么确保线程被终止,要么确保线程被终止,或者从不明确释放它并允许操作系统在应用程序关闭时终止它。 / p>

你对TThread类有什么看法(除了你不必使用的可怕的同步/ WaitFor / OnTerminate)?

答案 1 :(得分:2)

您无法传递实例方法,因为它是错误的类型。您尝试使用procInObject永远不会有效。

线程过程是一个简单的过程,它不是类的方法。为了将实例放入您的线程,您需要使用Params参数传递它。

线程函数如下所示:

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

该程序现在可以调用Obj上的方法。

CreateThread的调用:

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