2011-07-15 24 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

整数变量唯一不对齐的时候是它是打包记录的成员。全局,本地,参数和类字段始终对齐。 –

相关问题