【问题标题】:How to set stack size in TThread?如何在 TThread 中设置堆栈大小?
【发布时间】:2014-07-31 04:10:05
【问题描述】:

如何在TThread 中设置自定义堆栈大小?我正在尝试重新引入TThread 的构造函数,但它说ThreadProc 丢失了,但它就在System.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;

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

【问题讨论】:

  • ThreadProc 函数不供公众使用。它也将在单元的interface 部分中定义。因此编译器看不到它。

标签: delphi delphi-xe6


【解决方案1】:

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

如果您只是不顾一切地想让您的 hack 工作,那么您需要找到在 Classes 单元的实现部分中声明的 ThreadProc 函数的地址。一些可能的方法:

  1. 运行时拆解TThread.Create,读出ThreadProc的地址。
  2. 创建一个虚拟线程,查看其调用堆栈以查找ThreadProc 的地址。
  3. 绕道钩BeginThread。创建一个虚拟线程。注意传递的线程过程的地址。那是ThreadProc

madExcept 的源代码是此类黑客攻击的一个很好的想法来源。

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

【讨论】:

  • 你可以使用任何你喜欢的 detour 库
【解决方案2】:

我不知道,是否可以在创建线程后设置堆栈大小。也许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 不允许程序员指定堆栈大小,如果有人知道原因,我会很感兴趣。

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

      【解决方案4】:

      对于 Delphi 10.3 RIO 及更高版本,现在有一个重载的构造函数,允许您在 Windows 平台上为 TThread 设置 ReservedStackSize。

      {$IF Defined(MSWINDOWS)}
          constructor Create(CreateSuspended: Boolean; ReservedStackSize: NativeUInt); overload;
      {$ENDIF MSWINDOWS}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-08-28
        • 2015-08-08
        • 1970-01-01
        • 2016-12-07
        • 2011-07-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多