Multithreading 通用线程安全属性

Multithreading 通用线程安全属性,multithreading,delphi,generics,thread-safety,delphi-xe5,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

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

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;
TLockedProp=class
私有的
FMyProp:MyType;
PropLock:TObject;
程序SetMyProp(常量值:MyType);
函数GetMyProp:MyType;
出版
属性值:MyType读取GetMyProp写入SetMyProp;
公众的
构造函数创建;
毁灭者毁灭;推翻
结束;
{TLockedProp}
构造函数TLockedProp.Create;
开始
继承;
PropLock:=TObject.create
结束;
析构函数TLockedProp.Destroy;
开始
PropLock.Free;
继承;
结束;
函数TLockedProp.GetMyProp:MyType;
开始
t监视器输入(PropLock);
结果:=FMyProp;
t监视器出口(支撑锁);
结束;
过程TLockedProp.SetMyProp(常量值:MyType);
开始
t监视器输入(PropLock);
FMyProp:=值;
t监视器出口(支撑锁);
结束;
有什么我忽略的问题吗? 这是一些使用此属性类的代码。告诉我你的想法

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;
TBgThread=class(TThread)
私有的
FPaused:TLockedProp;
FCount:TLockedProp;
过程更改计数(pPlusMin:integer);
函数GetPaused:布尔型;
函数GetCount:integer;
公开的
构造函数创建;
毁灭者毁灭;推翻
{切换暂停}
程序暂停播放;
受保护的
程序执行;推翻
出版
属性暂停:布尔读取已暂停;
属性计数:整数读取GetCount;
结束;
构造函数TBgThread.Create();
开始
继承创建(true);;
FPaused:=TLockedProp.create;
FPaused.Value:=false;
FCount:=TLockedProp.create;
F计数值:=0;
结束;
析构函数TBgThread.Destroy;
开始
免费的;
FCount.free;
继承;
结束;
过程TBgThread.Execute;
开始
继承;
重复
如果没有暂停,则开始
尝试
//做点什么
最后
更改计数(上升1),;
结束;
结束其他
睡眠(90);
直至终止;
结束;
函数TBgThread.GetCount:整数;
开始
结果:=FCount.Value;
结束;
过程TBgThread.ChangeCount(pPlusMin:integer);
开始
FCount.Value:=FCount.Value+pPlusMin;
结束;
函数TBgThread.GetPaused:boolean;
开始
结果:=FPaused.值;
结束;
程序TBgThread.PausePlay;
开始
FPaused.Value:=非FPaused.Value;
结束;

您的代码很好,将序列化对属性的读/写访问。我唯一要说的是,您不需要创建单独的锁对象。您可以移除
PropLock
并锁定
Self

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

  • 我使用关键部分而不是
    TMonitor
    ,因为我仍然不信任
    TMonitor
    。早期版本有很多bug,这削弱了我的信心。但是,我怀疑
    TMonitor
    代码现在很可能是正确的。所以我看你没有理由改变
  • 我将try/finally与锁定和解锁的代码一起使用。就我而言,这可能有点悲观,因为很难看到如何有效地从getter和setter方法中的异常中恢复。我想是习惯的力量吧
  • 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;
    
    类型
    TThreadsafe=class
    私有的
    鸥群:TCriticalSection;
    f值:T;
    函数GetValue:T;
    程序设置值(const NewValue:T);
    公众的
    构造函数创建;
    毁灭者毁灭;推翻
    属性值:T读取GetValue写入SetValue;
    结束;
    {TThreadsafe}
    构造函数TThreadsafe.Create;
    开始
    继承;
    FLock:=TCriticalSection.Create;
    结束;
    析构函数TThreadsafe.Destroy;
    开始
    羊群。自由;
    继承;
    结束;
    函数TThreadsafe.GetValue:T;
    开始
    羊群。获取;
    尝试
    结果:=fv值;
    最后
    3.释放;
    结束;
    结束;
    过程TThreadsafe.SetValue(const NewValue:T);
    开始
    羊群。获取;
    尝试
    FValue:=新值;
    最后
    3.释放;
    结束;
    结束;
    

    我想写这门课只有一种方法

    谢谢你的回答,我真的很感激你分享了你的课程版本。作为一名程序员,我更加相信自己能够想出这个解决方案。我只有一年的德尔福经验;)。请注意,如果保存其缓冲区的类小于CPU缓存线,则关键部分可能存在性能问题。请参阅,在类定义中添加一个小的对齐缓冲区,并依赖操作系统关键部分而不是TCriticalSection类,可能会更好/更安全。如何编写示例来演示如何使用此类?@peiman有一个公共属性。有多少种可能的方法可以使用它呢?我还不明白这个概念,我想举个例子:)所以你的答案对我没有帮助:|我必须为每个共享变量创建一个
    TThreadsafe
    ?!