2014-06-10 13 views
5

Jak ustawić niestandardowy rozmiar stosu w TThread? Próbuję ponownie wprowadzić konstruktora z TThread, ale mówi, że ThreadProc brakuje jej tam w System.Classes.Jak ustawić rozmiar stosu w 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 Błąd] Project5.dpr (29): E2003 nielegalna Identyfikator: 'ThreadProc'

+0

Opcja 'ThreadProc' funkcja nie jest do użytku publicznego. Byłoby to również zdefiniowane w części "interfejsu" jednostki. Dlatego kompilator nie może tego zobaczyć. – TLama

Odpowiedz

7

Nie wiem, czy można ustawić rozmiar stosu po utworzeniu wątku. Może być pomocne SetThreadStackGuarantee?

Możesz utworzyć wątek od podstaw, używając BeginThread, ale jest to dość skomplikowane. Mam tutaj obejście tego problemu przy użyciu Detours. Zauważ, że istnieje kilka wariantów Detours. Myślę, że tylko Cromis.Detours jest kompatybilny z 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. 

nie wiem dlaczego Embt nie pozwala programiście określić rozmiar stosu, jeśli ktoś zna powód, to będzie bardzo interesujące dla mnie.

3

prostu nie ma sposobu, aby kontrolować wielkość stos za TThread. Z jakiegokolwiek powodu projektanci TThread nie zawarli parametru wielkości stosu w konstruktorze TThread. Jest to wyraźnie pominięcie. Należy bezpośrednio zadzwonić pod numer BeginThread lub CreateThread.

Jeśli jesteś po prostu zdesperowany, aby wykonać swoją pracę hackową, musisz znaleźć adres funkcji ThreadProc zadeklarowanej w sekcji implementacji jednostki Classes. Niektóre z możliwych podejść:

  1. Disassemble TThread.Create w czasie wykonywania odczytać adres ThreadProc.
  2. Utworzyć sztuczny wątek, który wygląda na stosie wywołań, aby znaleźć adres ThreadProc.
  3. Hak BeginThread za pomocą objazdu. Utworzyć sztuczny wątek. Zwróć uwagę na adres przekazanej procedury wątku. To jest ThreadProc.

Dobrym źródłem pomysłów na tego typu hakowanie jest kod źródłowy dla madExcept.

Innym sposobem zastosowania hacka byłoby ponowne użycie objazdu pod numerem BeginThread. Następnie można użyć zmiennej lokalnej wątku, aby podać rozmiar stosu. Wartość high(LongWord) dla zmiennej lokalnej tego wątku oznaczałaby "użyj wartości przekazanej jako parametr", a każda inna wartość byłaby wartością używaną przez oderwane BeginThread.

+0

Można to zrobić za pomocą 'Delphi Detours'. – user3725897

+0

Możesz użyć dowolnej biblioteki objazdów, którą lubisz –

3

Jak wskazuje David, nie można kontrolować wielkości stosu dla wątków utworzonych przy użyciu klasy TThread. Trzeba samemu utworzyć bieżący wątek, używając BeginThread lub CreateThread.

Jednakże, jeśli nie trzeba różne rozmiary stosu dla każdego wątku w aplikacji:
Następnie można ustawić domyślny rozmiar stosu przy użyciu opcji z linkami do Minimum stosu i maksymalny rozmiar stosu.

Albo ustawić opcję w opcjach projektu, lub użyć dyrektyw: {$M minstacksize,maxstacksize} {$MINSTACKSIZE number} {$MAXSTACKSIZE number}

Powiązane problemy