通用Threadsafe属性

时间:2013-10-31 09:56:41

标签: multithreading delphi generics thread-safety delphi-xe5

我创建了这个“线程安全”的通用属性,我可以在主线程和后台线程之间使用。我之所以这样做是因为我厌倦了为所有属性和变量创建锁定对象。

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;

我有什么问题可以忽略吗? 这是使用此属性类的一些代码。告诉我你的想法。

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;

1 个答案:

答案 0 :(得分:16)

您的代码很好,并将序列化对该属性的读/写访问权限。我要做的唯一评论是你不需要创建一个单独的锁对象。您可以删除PropLock并锁定Self

我的代码库中有一个几乎相同的类。唯一的区别是:

  1. 我使用的是关键部分而不是TMonitor,因为我仍然不信任TMonitor。早期版本有许多错误,这使我的信心受损。但是,我怀疑TMonitor代码现在最有可能是正确的。所以我认为你没有理由改变。
  2. 我使用try / finally和锁定和解锁的代码。这对我来说可能有点悲观,因为很难看出如何从getter和setter方法中的异常中有效地恢复。我想是习惯的力量。
  3. FWIW,我的班级版本如下:

    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;
    

    我想真的只有一种方法来写这个课!