使用单个命令锁定和解锁资源
Posted
技术标签:
【中文标题】使用单个命令锁定和解锁资源【英文标题】:Lock and unlock resources with single command 【发布时间】:2015-01-18 01:17:01 【问题描述】:我正在使用线程,这就是我使用互斥锁来锁定共享资源的原因。锁定的基本用法是将资源放入锁定/解锁块中。
procedure RefreshData;
begin
DataLock;
GetData;
GetSettings;
CheckValues;
...
DataUnlock;
end;
因为总是有一对锁定/解锁,所以我开始考虑简化的锁定/解锁方法,它会在不再需要时自动解锁资源。
所以我的想法是引入新的过程,它将作为输入参数对 precedure 的引用。这将使我能够使用匿名方法。
代码类似于:
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;
这种方法有什么意义吗?或者有更好甚至更简单的解决方案吗?
感谢和问候。
【问题讨论】:
你是否关心性能? 最简单的解决方案是,如果编译器对 Lock() 语句具有原生支持,例如 C#:msdn.microsoft.com/en-us/library/c5kehkcz.aspx。我个人将代码模板用于锁定/解锁对。 @David:是的,我关心性能。有没有估计多少开销会导致这种方法?我猜锁定/解锁对在性能方面仍然是更好的方法。 这是一个带有接口的nice approach
。
除此之外......只是一个简短的问题。在同一线程中嵌套锁定/解锁块时,例如:mtx1.Acquire; mtx1.获取;做一些东西; mtx1.release; mtx1.release。据我所知,当互斥锁已由同一线程拥有时不会发生锁定,但释放情况如何?哪个版本将解锁资源,第一个或第二个调用?我不确定,但我想我在某处读到系统有内部计数,所以我认为最后一个版本将真正解锁资源。我说的对吗?
【参考方案1】:
这种方法远非完美,因为我从您的代码中了解到,每个应用程序都有一个锁。最好是每个独立的数据实体都有自己的锁。所以你会有一个像这样的抽象类:
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——作者推荐了类似的做法。
【讨论】:
以上是关于使用单个命令锁定和解锁资源的主要内容,如果未能解决你的问题,请参考以下文章