如何在TThread中设置堆栈大小?

时间:2014-06-10 11:51:48

标签: delphi delphi-xe6

如何在TThread中设置自定义堆栈大小?我正在尝试重新引入TThread的构造函数,但它表示ThreadProcSystem.Classes中缺少type TThreadHelper = class helper for TThread constructor Create(const CreateSuspended: Boolean = False; const StackSize: Integer = 0); reintroduce; end; { TThreadHelper } constructor TThreadHelper.Create(const CreateSuspended: Boolean; const StackSize: Integer); begin Self.FSuspended := not Self.FExternalThread; Self.FCreateSuspended := CreateSuspended and not Self.FExternalThread; if not Self.FExternalThread then begin Self.FHandle := BeginThread(nil, StackSize, @ThreadProc, Pointer(Self), CREATE_SUSPENDED, Self.FThreadID); if Self.FHandle = 0 then raise EThread.CreateResFmt(@SThreadCreateError, [SysErrorMessage(GetLastError)]); end else begin Self.FHandle := Winapi.Windows.GetCurrentThread; Self.FThreadId := GetCurrentThreadId; end; end;

{{1}}
  

[dcc32错误] Project5.dpr(29):E2003未声明的标识符:   ' ThreadProc的'

3 个答案:

答案 0 :(得分:7)

我不知道,如果你可以在创建一个线程后设置堆栈大小。也许SetThreadStackGuarantee会有帮助吗?

您可以使用BeginThread从头开始创建一个线程,但它非常复杂。我在这里使用Detours进行了解决方法。请注意,有几个Detours变体。我认为只有Cromis.Detours与x64兼容。

unit IndividualStackSizeForThread;

interface

uses 
  System.Classes,
  Cromis.Detours { http://www.cromis.net/blog/downloads/cromis-ipc/ };

type
  TThreadHelper = class helper for TThread
    constructor Create(CreateSuspended: Boolean; StackSize: LongWord);
 end;

implementation

var
  TrampolineBeginThread: function(SecurityAttributes: Pointer; StackSize: LongWord;
    ThreadFunc: TThreadFunc; Parameter: Pointer; CreationFlags: LongWord; 
    var ThreadId: TThreadID): THandle = nil;

threadvar
  StackSizeOverride: LongWord;

function InterceptBeginThread(SecurityAttributes: Pointer; StackSize: LongWord;
  ThreadFunc: TThreadFunc; Parameter: Pointer; CreationFlags: LongWord;
  var ThreadId: TThreadID): THandle;
const
  STACK_SIZE_PARAM_IS_A_RESERVATION = $00010000; // http://msdn.microsoft.com/en-us/library/windows/desktop/ms682453(v=vs.85).aspx
begin
  if StackSizeOverride <> 0 then
  begin
    CreationFlags := CreationFlags or STACK_SIZE_PARAM_IS_A_RESERVATION;
    StackSize := StackSizeOverride;
    StackSizeOverride := 0;
  end;

  Result := TrampolineBeginThread(SecurityAttributes, StackSize, ThreadFunc, 
    Parameter, CreationFlags, ThreadId);
end;

constructor TThreadHelper.Create(CreateSuspended: Boolean; StackSize: LongWord);
begin
  StackSizeOverride := StackSize;
  inherited Create(CreateSuspended);
end;

initialization

TrampolineBeginThread := InterceptCreate(@BeginThread, @InterceptBeginThread);

finalization

InterceptRemove(@TrampolineBeginThread, @InterceptBeginThread);

end.

我不知道为什么Embt不允许程序员指定堆栈大小,如果有人知道原因,那对我来说会非常有趣。

答案 1 :(得分:3)

使用TThread无法控制堆栈大小。无论出于何种原因,TThread的设计者都未能在TThread的构造函数中包含堆栈大小参数。这显然是一个遗漏。您应该直接致电BeginThreadCreateThread

如果您只是急于让黑客工作,那么您需要找到ThreadProc单元的实现部分中声明的Classes函数的地址。一些可能的方法:

  1. 在运行时反汇编TThread.Create以读出ThreadProc
  2. 的地址
  3. 创建一个虚拟线程,查看其调用堆栈以查找ThreadProc
  4. 的地址
  5. 使用绕道钩BeginThread。创建一个虚拟线程。请注意传递的线程过程的地址。那是ThreadProc
  6. 这种黑客行为的一个很好的想法来源是madExcept的源代码。

    另一种应用黑客的方法是再次使用BeginThread绕道而行。然后,您可以使用线程局部变量来提供堆栈大小。该线程局部变量的值high(LongWord)表示“使用作为参数传递的值”,而任何其他值将是绕道BeginThread使用的值。

答案 2 :(得分:3)

正如David所指出的,您无法控制使用TThread类创建的线程的堆栈大小。您必须使用BeginThreadCreateThread

自行创建实际线程

但是,如果您的应用程序中的每个线程都不需要不同的堆栈大小:
然后,您可以使用最小堆栈大小最大堆栈大小的链接选项设置默认堆栈大小。

在项目选项中设置选项,或使用指令:{$M minstacksize,maxstacksize} {$MINSTACKSIZE number} {$MAXSTACKSIZE number}