2013-10-31 15 views
10

Tôi đã tạo thuộc tính chung "chủ đề" chung này, mà tôi có thể sử dụng giữa chuỗi chính và Chủ đề nền. Tôi đã tạo ra nó bởi vì tôi đã mệt mỏi vì đã tạo ra Lock-Objects cho tất cả các thuộc tính và biến của tôi.Generic Threadsafe Property

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; 

Có vấn đề gì tôi đang xem không? Đây là một số mã sử dụng lớp thuộc tính này. Nói cho tôi biết bạn nghĩ gì.

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; 

Trả lời

15

Mã của bạn là tốt và sẽ tuần tự hóa quyền truy cập đọc/ghi vào thuộc tính. Nhận xét duy nhất mà tôi sẽ làm là bạn không cần phải tạo một đối tượng khóa riêng biệt. Bạn có thể xóa PropLock và khóa trên Self để thay thế.

Tôi có một lớp học gần như giống hệt nhau trong cơ sở mã của mình. Sự khác biệt duy nhất là:

  1. Tôi sử dụng phần quan trọng thay vì TMonitor vì tôi vẫn không tin tưởng TMonitor. Các phiên bản đầu tiên đã có một số lỗi và làm giảm sự tự tin của tôi. Tuy nhiên, tôi nghi ngờ rằng mã TMonitor rất có thể là chính xác ngay bây giờ. Vì vậy, tôi không thấy lý do gì để bạn thay đổi.
  2. Tôi sử dụng thử/cuối cùng bằng mã khóa và mở khóa. Điều này có lẽ là một chút bi quan về phía tôi, bởi vì rất khó để xem làm thế nào bạn có thể khôi phục lại một cách hữu ích từ các ngoại lệ trong các phương thức getter và setter. Lực lượng của thói quen tôi giả sử.

FWIW, phiên bản của tôi về lớp học của bạn trông như thế này:

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; 

Tôi đoán có thực sự chỉ là một cách để viết lớp này!

+1

Thnx cho câu trả lời của bạn và tôi thực sự đánh giá cao sự thật là bạn đã chia sẻ phiên bản của lớp học. Làm cho tôi cảm thấy tự tin hơn với tư cách là một lập trình viên mà tôi có thể tự mình đưa ra giải pháp này. chỉ có 1 năm của delphi dưới vành đai của tôi;). –

+0

Lưu ý rằng một phần quan trọng có thể có vấn đề hiệu suất, nếu lớp giữ bộ đệm của nó nhỏ hơn dòng bộ nhớ cache CPU. Xem https://www.delphitools.info/2011/11/30/fixing-tcriticalsection/ Có thể tốt hơn/an toàn hơn để thêm một bộ đệm căn chỉnh nhỏ vào định nghĩa lớp, và dựa vào phần quan trọng của hệ điều hành, thay vì lớp TCriticalSection . –