2014-06-10 51 views
5

如何在TThread中设置自定义堆栈大小?我试图重新引入TThread的构造函数,但它说ThreadProcSystem.Classes中缺失。如何在TThread中设置堆栈大小?

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的'

+0

的'ThreadProc'功能不供公众使用。它也会在单元的'interface'部分中定义。因此编译器无法看到它。 – TLama

回答

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不允许程序员指定的堆栈大小,如果有人知道的原因,这将是对我来说非常有趣。

3

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

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

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

这种黑客行为的一个好主意是madExcept的源代码。

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

+0

它也可以通过'Delphi Detours'完成。 – user3725897

+0

你可以使用任何你喜欢的绕道库 –

3

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

不过,如果你并不需要使用不同的堆栈大小为应用程序中的每个线程:
然后你可以设置使用连接选项的默认堆栈大小最小堆栈大小最大堆栈大小

无论是设置在项目选择的选项,或使用指令:{$M minstacksize,maxstacksize} {$MINSTACKSIZE number} {$MAXSTACKSIZE number}