2014-11-20 2 views
5

Я работаю с потоками, и именно поэтому я использую мьютексы для блокировки общих ресурсов. Базовое использование блокировки заключается в размещении ресурсов в блоке блокировки/разблокировки.Блокировка и разблокировка ресурсов с помощью одной команды

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

Потому что всегда есть пара блокировки/разблокировки Я начал думать об упрощенной блокировке/разблокировка подхода, который бы автообновление разблокировать ресурсы, когда больше не нужно.

Итак, моя идея состояла в том, чтобы ввести новую процедуру, которая будет принимать в качестве входного параметра ссылку на прецедент. Это даст мне возможность использовать анонимный метод.

Код будет что-то вроде:

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; 

Имеет такой подход какой-то смысл или есть лучше, или даже проще решение этой проблемы?

Спасибо и приветствую.

+0

Вы заботитесь о производительности или нет? –

+2

Простейшим решением было бы, если бы у компилятора была встроенная поддержка оператора Lock(), как в C#: http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx. Лично я использую шаблоны кода для пар блокировки/разблокировки. –

+0

@ Давид: Да, я забочусь о производительности. Есть ли какая-либо оценка того, сколько накладных расходов может вызвать такой подход? Я думаю, что пара Lock/Unlock по-прежнему лучше подходит с точки зрения производительности. – Nix

ответ

0

Этот подход далек от совершенства, потому что, как я понял из вашего кода, у вас всего одна блокировка для всего приложения. Лучше, когда каждый независимый объект данных имеет свой собственный замок. Таким образом, у вас будет абстрактный класс следующим образом:

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

Затем наследуйте другие классы из этого абстрактного класса, который реализует блокировку.

 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 - это наиболее эффективные ключи синхронизации, реализованные в Windows до сих пор. Он практически свободен - не потребляет практически никаких системных ресурсов, если нет конфликтов потоков, и не вызывает дорогостоящий контекстный коммутатор, когда только один поток использует данные.

После того, как я отправил ответ, вы нашли хорошую статью в Интернете - http://blog.synopse.info/post/2016/01/09/Safe-locks-for-multi-thread-applications - автор рекомендует аналогичный подход.

Смежные вопросы