2014-11-20 20 views
5

Pracuję z wątkami i to jest powód, dla którego używam muteksów do blokowania współdzielonych zasobów. Podstawowym zastosowaniem blokowania jest umieszczenie zasobów w bloku blokowania/odblokowywania.Blokowanie i odblokowywanie zasobów za pomocą pojedynczego polecenia

procedure RefreshData; 
begin  
    DataLock; 
     GetData; 
     GetSettings; 
     CheckValues; 
     ... 
    DataUnlock; 
end; 

Ponieważ zawsze istnieje para Zablokuj/Odblokuj zacząłem myśleć o uproszczonej zablokowanie/odblokowanie podejście, które automatical odblokować zasoby, gdy nie jest już potrzebny.

Tak więc moim pomysłem było wprowadzenie nowej procedury, która jako parametr wejściowy przyjmowałaby odniesienie do precedensu. To da mi możliwość korzystania z anonimowej metody.

kod byłoby coś jak:

type TBaseProc = reference to procedure; 

procedure TMyObject.LockMethod(AMeth: TBaseProc); 
begin 
    DataLock; 
    try 
    AMeth; 
    finally 
    DataUnlock; 
    end; 
end; 


procedure TForm1.RefreshData; 
begin 
    MyObject.LockMethod(
    procedure 
    begin 
    GetData; 
    GetSettings; 
    CheckValues; 
    ... 
    end; 
); 

end; 

Ma to podejście sensu lub jest tam lepiej lub nawet łatwiejsze rozwiązanie tego?

Dzięki i pozdrawiam.

+0

Czy zależy Ci na wydajności, czy nie? –

+2

Najprostszym rozwiązaniem byłoby, gdyby kompilator miał natywną obsługę instrukcji Lock(), jak w C#: http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx. Osobiście używam szablonów kodu dla par zablokowanych/odblokowanych. –

+0

@ David: Tak, zależy mi na wydajności. Czy są jakieś szacunki dotyczące tego, na ile obciążenie mogłoby spowodować takie podejście? Sądzę, że para Lock/Unlock jest wciąż lepszym podejściem pod względem wydajności. – Nix

Odpowiedz

0

Podejście to jest dalekie od doskonałości, ponieważ, jak rozumiem z twojego kodu, masz po prostu jedną blokadę na całą aplikację. Lepiej jest, gdy każda niezależna jednostka danych ma swój własny zamek. Więc masz klasę abstrakcyjną taką jak ta:

type 
    TAbstractData = class 
    private 
     CriticalSection: TRtlCriticalSection 
    public 
     constructor Create; 
     procedure Lock; 
     procedure Unlock; 
     destructor Destroy; override; 
    end; 

Następnie dziedziczą inne klasy z tej abstrakcyjnej klasy, która implementuje blokowanie.

 constructor TAbstractData .Create; 
     begin 
     inherited Create; 
     InitializeCriticalSection(CriticalSection); 
     end; 

     procedure TAbstractData.Lock; 
     begin 
     EntercriticalSection(CriticalSection); 
     end; 

     procedure TAbstractData.Unlock; 
     begin 
     LeaveSection(CriticalSection); 
     end; 

     procedure TAbstractData.Destroy; 
     begin 
     DeleteCriticalSection(CriticalSection); 
     inherited Destroy; 
     end; 

CriticalSection to najbardziej efektywny proces synchronizacji, dotychczas implementowany w systemie Windows. Jest praktycznie darmowy - nie zużywa prawie żadnych zasobów systemowych, chyba że istnieje rywalizacja o wątki i nie wywołuje drogiego przełącznika kontekstu, gdy tylko jeden wątek używa danych.

Po przesłaniu odpowiedzi, znalazłem dobry artykuł w Internecie - http://blog.synopse.info/post/2016/01/09/Safe-locks-for-multi-thread-applications - autor zaleca podobne podejście.

Powiązane problemy