2012-06-07 31 views
1

我有一個單元是這樣的如何從沒有TThread的線程程序訪問類的成員?

type 
TMyClass = Class(TObject) 
private 
AnInteger  : Integer; 
MyThreadHandle : DWORD; 
procedure MyPrivateProcedure; 
public 
procedure MyPublicProcedure; 
end; 

procedure TMyClass.MyPrivateProcedure; 
procedure MyThread; stdcall; 
begin 
    if AnInteger <> 0 then MyPublicProcedure; 
end; 
var 
DummyID: DWORD; 
begin 
    MyThreadHandle := CreateThread(NIL,0,@MyThread,NIL,0, DummyID); 
end; 

procedure TMyClass.MyPublicProcedure; 
begin 
AnInteger := 0; 
end; 

我的目標是有一個主題(無TTthread請。),可以「訪問」的瓦爾/功能/過程就像它是類的一部分。此示例失敗是因爲它無法訪問變量,也無法訪問該過程。這只是一個例子,我知道Integer不能像這樣改變。對我來說,擁有屬於課程一部分的線程非常重要。我也嘗試將整數作爲指針(工作)傳遞給線程,但我仍然無法訪問類的過程/函數。有任何想法嗎?

+3

>沒有TTthread請<什麼是什麼原因呢? – MBo

+0

我使用控制檯應用程序。我想保持文件大小小。 –

+1

可以使用的TThread並保持文件大小小。看看[LVCL]( http://synopse.info/fossil/dir?name=LVCL),如果你想爲控制檯應用程序提供[輕量級TThread實現](http://synopse.info/fossil/artifact/2ca74af467aa3722ecc524ca2d011eb4f7af8480),但只能使用Delphi請注意內存管理如果你在你的應用程序中使用線程,呃希望設置一個全局變量:不使用TThread只有當你知道RTL內部時才知道你的進程不會進行任何內存分配。 –

回答

5

線程都有自己的堆棧指針,所以你不能訪問本地變量或參數(如隱藏的Self參數)在您的本地過程中(該函數聲明爲錯誤)。此外,如果它們從外部函數訪問變量(包括Self),則不能使用線程的本地過程。如果您將來要使用64位編譯器,則不能使用本地過程進行任何回調。

在你的情況下,你只需要修改你的過程的聲明並將它移到單元範圍中(使它成爲一個「獨立」過程,這允許你使用「Self」的線程回調參數)

function MyThread(MyObj: TMyClass): DWORD; stdcall; 
begin 
    if MyObj.AnInteger <> 0 then 
    MyObj.MyPublicProcedure; 
    Result := 0; 
end; 

procedure TMyClass.MyPrivateProcedure; 
var 
    DummyID: DWORD; 
begin 
    MyThreadHandle := CreateThread(nil, 0, @MyThread, Self, 0, DummyID); 
end; 
+0

優異!這就是我一直在尋找的!我忘了Self已經在自己的實例中(TMyClass.Create)。我幾乎和TMyClass一樣,而不是自己。再次感謝你! –

+1

您應該注意在從不同線程讀取/寫入時鎖定變量。 – stanleyxu2005

+0

這不是實現線程處理的方式。你應該調用exitthread並釋放線程句柄,除非你會鬆動資源。 –

6

您可以使用TThread並保持較小的文件大小。我認爲你會走上一條艱難的道路:重新發明輪子非常耗時,我可以告訴你! :)

下面是一些工作的代碼來初始化線程:

function ThreadProc(Thread: TThread): Integer; 
var FreeThread: Boolean; 
begin 
    if not Thread.FTerminated then 
    try 
    result := 0; // default ExitCode 
    try 
     Thread.Execute; 
    except 
     on Exception do 
     result := -1; 
    end; 
    finally 
    FreeThread := Thread.FFreeOnTerminate; 
    Thread.FFinished := True; 
    if Assigned(Thread.OnTerminate) then 
     Thread.OnTerminate(Thread); 
    if FreeThread then 
     Thread.Free; 
    EndThread(result); 
    end; 
end; 

constructor TThread.Create(CreateSuspended: Boolean); 
begin 
    IsMultiThread := true; // for FastMM4 locking, e.g. 
    inherited Create; 
    FSuspended := CreateSuspended; 
    FCreateSuspended := CreateSuspended; 
    FHandle := BeginThread(nil, 0, @ThreadProc, Pointer(Self), CREATE_SUSPENDED, FThreadID); 
    if FHandle = 0 then 
    raise Exception.Create(SysErrorMessage(GetLastError)); 
    SetThreadPriority(FHandle, THREAD_PRIORITY_NORMAL); 
end; 

也就是說,你傳遞對象爲pointer()線程創建API,這將作爲ThreadProc的獨特參數傳遞。

ThreadProc不應該是任何方法的一部分,而是全局的單元。

這裏是另一段代碼直接調用API來處理多線程壓縮,無開銷,並同步:

type 
    TThreadParams = record 
    bIn, bOut: pAESBlock; 
    BlockCount: integer; 
    Encrypt: boolean; 
    ID: DWORD; 
    AES: TAES; 
    end; 

{ we use direct Windows threads, since we don't need any exception handling 
    nor memory usage inside the Thread handler 
    -> avoid classes.TThread and system.BeginThread() use 
    -> application is still "officialy" mono-threaded (i.e. IsMultiThread=false), 
    for faster System.pas and FastMM4 (no locking) 
    -> code is even shorter then original one using TThread } 
function ThreadWrapper(var P: TThreadParams): Integer; stdcall; 
begin 
    with P do 
    AES.DoBlocks(bIn,bOut,bIn,bOut,BlockCount,Encrypt); 
    ExitThread(0); 
    result := 0; // make the compiler happy, but won't never be called 
end; 

procedure TAES.DoBlocksThread(var bIn, bOut: PAESBlock; Count: integer; doEncrypt: boolean); 
var Thread: array[0..3] of TThreadParams; // faster than dynamic array 
    Handle: array[0..3] of THandle; // high(Thread) is not compiled by XE2 
    nThread, i, nOne: integer; 
    pIn, pOut: PAESBlock; 
begin 
    if Count=0 then exit; 
    if {$ifdef USEPADLOCK} padlock_available or {$endif} 
    (SystemInfo.dwNumberOfProcessors<=1) or // (DebugHook<>0) or 
    (Count<((512*1024) div AESBlockSize)) then begin // not needed below 512 KB 
    DoBlocks(bIn,bOut,bIn,bOut,Count,doEncrypt); 
    exit; 
    end; 
    nThread := SystemInfo.dwNumberOfProcessors; 
    if nThread>length(Thread) then // a quad-core is enough ;) 
    nThread := length(Thread); 
    nOne := Count div nThread; 
    pIn := bIn; 
    pOut := bOut; 
    for i := 0 to nThread-1 do 
    with Thread[i] do begin // create threads parameters 
    bIn := pIn; 
    bOut := pOut; 
    BlockCount := nOne; 
    Encrypt := doEncrypt; 
    AES := self; // local copy of the AES context for every thread 
    Handle[i] := CreateThread(nil,0,@ThreadWrapper,@Thread[i],0,ID); 
    inc(pIn,nOne); 
    inc(pOut,nOne); 
    dec(Count,nOne); 
    end; 
    if Count>0 then 
    DoBlocks(pIn,pOut,pIn,pOut,Count,doEncrypt); // remaining blocks 
    inc(Count,nOne*nThread); 
    assert(integer(pIn)-integer(bIn)=Count*AESBlockSize); 
    assert(integer(pOut)-integer(bOut)=Count*AESBlockSize); 
    bIn := pIn; 
    bOut := pOut; 
    WaitForMultipleObjects(nThread,@Handle[0],True,INFINITE); 
    for i := 0 to nThread-1 do 
    CloseHandle(Handle[i]); 
end; 
+0

我將來會使用TThread。我會牢記這個例子。非常感謝你。 –

相關問題