2013-10-31 13 views
10

Bu "threadsafe" genel özelliğini oluşturdum, ana iş parçacığı ile arka plan iş parçacığı arasında kullanabileceğim. Bunu yaptım çünkü tüm özelliklerim ve değişkenlerim için Lock-Objects yaratmaktan bıktım.Genel Threadsafe Özelliği

TLockedProp<MyType> = class 
private 
    FMyProp:MyType; 
    PropLock:TObject; 
    procedure SetMyProp(const Value: MyType); 
    function GetMyProp: MyType; 
published 
    property Value:MyType read GetMyProp write SetMyProp; 
public 
    Constructor Create; 
    Destructor Destroy;override; 
end; 

{ TLockedProp<MyType> } 

constructor TLockedProp<MyType>.Create; 
begin 
    inherited; 
    PropLock:=TObject.create 
end; 

destructor TLockedProp<MyType>.Destroy; 
begin 
    PropLock.Free; 
    inherited; 
end; 

function TLockedProp<MyType>.GetMyProp: MyType; 
begin 
    TMonitor.Enter(PropLock); 
    result := FMyProp; 
    TMonitor.Exit(PropLock); 
end; 

procedure TLockedProp<MyType>.SetMyProp(const Value: MyType); 
begin 
    TMonitor.Enter(PropLock); 
    FMyProp := Value; 
    TMonitor.Exit(PropLock); 
end; 

Karşılaştığım herhangi bir sorun var mı? Bu özellik sınıfını kullanan bazı kodlardır. Bana ne düşündüğünü söyle.

TBgThread=class(TThread) 
    private  
    FPaused: TLockedProp<boolean>; 
    FCount:TLockedProp<integer>; 

    procedure ChangeCount(pPlusMin:integer); 
    function GetPaused:boolean; 
    function GetCount:integer; 
    public 
    constructor Create; 
    destructor Destroy;override; 
    {Toggle Pause} 
    procedure PausePlay; 
    protected 
    procedure Execute;override; 
    published 
    Property Paused:boolean read GetPaused; 
    Property Count:integer read GetCount; 
    end; 
constructor TBgThread.Create(); 
begin 
    inherited Create(true);; 
    FPaused:=TLockedProp<boolean>.create; 
    FPaused.Value:=false;  
    FCount:=TLockedProp<integer>.create; 
    FCount.Value:=0; 
end; 
destructor TBgThread.Destroy; 
begin 
    FPaused.Free; 
    FCount.free;  
    inherited; 
end; 
procedure TBgThread.Execute; 
begin 
    inherited; 
    Repeat 
    if not Paused then begin 
     Try 
      //do something 
     finally 
      ChangeCount(+1); 
     end; 
    end else 
     Sleep(90); 
    Until Terminated; 
end; 

function TBgThread.GetCount: integer; 
begin 
    Result:=FCount.Value; 
end; 

procedure TBgThread.ChangeCount(pPlusMin: integer); 
begin 
    FCount.Value:=FCount.Value+pPlusMin; 
end; 

function TBgThread.GetPaused: boolean; 
begin 
    result := FPaused.Value; 
end; 

procedure TBgThread.PausePlay; 
begin 
    FPaused.Value:=not FPaused.Value; 
end; 

cevap

15

Kodunuz gayet iyi ve tesisten okuma/yazma erişimini seri hale getirecektir. Yapacağım tek yorum, ayrı bir kilit nesnesi oluşturmanıza gerek olmamasıdır. PropLock'u kaldırabilir ve bunun yerine Self'u kilitleyebilirsiniz.

Kod tabanımda hemen hemen aynı bir sınıfa sahibim. Sadece farklılıklar şunlardır: Hala TMonitor güvenmiyorum çünkü

  1. ben TMonitor yerine kritik bölümünü kullanabilirsiniz. İlk sürümlerde birtakım hatalar vardı ve bu da beni güvendi. Ancak, şu anda TMonitor kodunun büyük olasılıkla doğru olduğunu sanıyorum. Yani değişmen için bir sebep göremiyorum.
  2. Kilitleme ve kilit açma kodunu kullanarak/son olarak kullanmayı deneyin. Bu belki de benim için biraz kötümser, çünkü alıcı ve ayarlayıcı yöntemlerindeki istisnalardan nasıl yararlanabileceğinizi görmek zor. Sanırım alışkanlık gücü.

FWIW, sınıfın benim sürümü aşağıdaki gibidir:

type 
    TThreadsafe<T> = class 
    private 
    FLock: TCriticalSection; 
    FValue: T; 
    function GetValue: T; 
    procedure SetValue(const NewValue: T); 
    public 
    constructor Create; 
    destructor Destroy; override; 
    property Value: T read GetValue write SetValue; 
    end; 

{ TThreadsafe<T> } 

constructor TThreadsafe<T>.Create; 
begin 
    inherited; 
    FLock := TCriticalSection.Create; 
end; 

destructor TThreadsafe<T>.Destroy; 
begin 
    FLock.Free; 
    inherited; 
end; 

function TThreadsafe<T>.GetValue: T; 
begin 
    FLock.Acquire; 
    Try 
    Result := FValue; 
    Finally 
    FLock.Release; 
    End; 
end; 

procedure TThreadsafe<T>.SetValue(const NewValue: T); 
begin 
    FLock.Acquire; 
    Try 
    FValue := NewValue; 
    Finally 
    FLock.Release; 
    End; 
end; 

ben bu sınıfı yazmak için gerçekten sadece bir yolu var sanırım!

+1

Cevabınız için Thnx, ve sınıfınızın sürümünü paylaştığınız için gerçekten minnettarım. Bu çözümle kendim gelebildiğim bir programcı olarak kendimi daha güvende hissetmemi sağlıyor. kemerimin altında sadece 1 yıl delphi;). –

+0

Önemli bir bölümün arabellek tutan sınıfı CPU önbellek satırından küçükse performans sorunlarının olabileceğini unutmayın. Bkz. Https://www.delphitools.info/2011/11/30/fixing-tcriticalsection/ Sınıf tanımına küçük bir hizalama tamponu eklemek ve TCriticalSection sınıfı yerine OS kritik bölümüne güvenmek daha iyi/güvenli olabilir. . –