2011-07-15 25 views
3

我想同步線程來訪問一個公共變量。 想象一下,我有N個線程,每個線程都可以訪問一個類型爲TSyncThreds的變量的全局實例。TCriticalSection是否允許多線程訪問變量?

我可以調用IncCount,DecCount方法嗎?或者,我會遇到併發線程訪問同一個對象實例的問題?

我只是syncronize的訪問FCcounter變量...

type 
    TSyncThreads = class 

    public 
    FCounterGuard: TCriticalSection; 
    FCounter: integer; 
    FSimpleEvent: TSimpleEvent; 

    constructor Create(); 
    procedure Wait(); 
    procedure IncCounter(); 
    procedure DecCounter(); 
    end; 


var 
    SyncThread: TSyncThreads; 

implementation 
uses 
    Math, Windows, Dialogs; 



{ TSyncThreads } 

procedure TSyncThreads.DecCounter; 
begin 
    FCounterGuard.Acquire; 
    Dec(FCounter); 
    if FCounter = 0 then 
    FSimpleEvent.SetEvent; 
    FCounterGuard.Release; 
end; 

procedure TSyncThreads.IncCounter; 
begin 
    FCounterGuard.Acquire; 
    Inc(FCounter); 
    FCounterGuard.Release; 
end; 

constructor TSyncThreads.Create(); 
begin 
    FCounter := 0; 
    FSimpleEvent := TSimpleEvent.Create; 
    FCounterGuard := TCriticalSection.Create; 
    FSimpleEvent.ResetEvent; 
end; 

procedure TSyncThreads.Wait; 
var 
    ret: TWaitResult; 
begin 
    ret := FSimpleEvent.WaitFor(INFINITE); 
end; 
+0

您應該使用try/finally塊將調用包裝爲Acquure/Release,以確保在按住關鍵部分時出現問題時調用Release。否則,它可能永遠不會釋放,無論等待獲得什麼,都會受到阻止。 – 2011-07-15 07:36:23

回答

8

是的,你的代碼是好的,如果有點大材小用了手頭的任務。你擔心多線程訪問同一個對象,但這正是TCriticalSection和TEvent等同步對象的設計目的。想象一下,如果不能同時訪問這些類,那將是多麼毫無意義。

您並不需要一個關鍵部分來保護對櫃檯的訪問。您可以使用InterlockedIncrement和InterlockedDecrement進行更輕量級的訪問。它們返回變量的前一個值,因此如果InterlockedDecrement返回1,那麼您就知道該設置事件了。

如果在計數器上有一個上限,那麼你甚至可以避免所有這些代碼並使用信號量代替。或者你可以給每個線程設置自己的事件,然後使用WaitForMultipleObjects等待所有的事件;一旦所有的線程都設置了它們的事件,它就會返回,所以你不必同步對任何共享變量的訪問。

+0

謝謝! 我喜歡Interlocked soilution。 –

+0

注意 - 要使用Interlocked *功能,計數器的地址必須可以被4整除。或者,使用我的TGp4AlignedInt記錄,它提供了互鎖功能等等,可在http://gpdelphiunits.googlecode.com/svn/trunk/上找到。 SRC/GpStuff.pas。 – gabr

+0

整數變量唯一不對齊的時候是它是打包記錄的成員。全局,本地,參數和類字段始終對齊。 –

相關問題