Delphi-有没有与C#lock等价的东西?
我正在用Delphi编写一个多线程应用程序,需要使用一些东西来保护共享资源 在C#中,我会使用“lock”关键字: 在Delphi中我找不到任何类似的方法,我只找到了TThread.Synchronize(someMethod)方法,它通过在主VCL线程中调用someMethod来防止潜在的冲突,但这并不是我想要做的 编辑:我使用的是Delphi 6(Un),幸运的是,您不能在Delphi 6中锁定任意对象(尽管您可以在更新的版本,2009和更高版本中锁定),因此您需要有一个单独的锁定对象,通常是一个关键部分 (注意:文档来自FreePascal,但也存在于Delphi中): 示例代码:Delphi-有没有与C#lock等价的东西?,c#,delphi,multithreading,delphi-6,C#,Delphi,Multithreading,Delphi 6,我正在用Delphi编写一个多线程应用程序,需要使用一些东西来保护共享资源 在C#中,我会使用“lock”关键字: 在Delphi中我找不到任何类似的方法,我只找到了TThread.Synchronize(someMethod)方法,它通过在主VCL线程中调用someMethod来防止潜在的冲突,但这并不是我想要做的 编辑:我使用的是Delphi 6(Un),幸运的是,您不能在Delphi 6中锁定任意对象(尽管您可以在更新的版本,2009和更高版本中锁定),因此您需要有一个单独的锁定对象,通常
type
TSomeClass = class
private
FLock : TCriticalSection;
public
constructor Create();
destructor Destroy; override;
procedure SomeMethod;
end;
constructor TSomeClass.Create;
begin
FLock := TCriticalSection.Create;
end;
destructor TSomeClass.Destroy;
begin
FreeAndNil(FLock);
end;
procedure TSomeClass.SomeMethod;
begin
FLock.Acquire;
try
//...do something with mySharedObj
finally
FLock.Release;
end;
end;
如上所述,对于不在本地范围外调用且不获取任何其他锁的短代码,您可以通过
SyncObjs.TCriticalSection
,使用关键部分 对于更长/更复杂的代码,您可以使用
SyncObjs.TMutex
,它是可等待的(带有超时),如果所属线程死亡,它不会暂停,并且可以通过名称与其他进程共享。使用这些包装器可以更轻松地更改同步层
在任何情况下,都要小心这里的龙:虽然不像c#那么简单,但下面的内容可能适合您。
with Lock(mySharedObj) do
begin
//...do something with mySharedObj
UnLock;
end;
简而言之
- 为您希望保护的每个实例保留一个列表
- 当第二个线程调用
时,将在内部列表中搜索现有锁。如果未找到现有锁,将创建新锁。如果另一个线程仍具有锁,则新线程将被阻塞李>锁(mySharedObj)
是必需的,因为我们无法确定在调用Unlock
的方法的末尾,对ILock实例的引用是否会超出范围。(如果可以,可以删除Lock
解锁
)
这是可以考虑的,但它会涉及到混乱与_AddRef&_发布
Delphi 6中没有等效项。从Delphi2009开始,您可以使用这些方法获取任意对象上的锁
System.TMonitor.Enter(obj);
try
// ...
finally
System.TMonitor.Exit(obj);
end;
(您需要“系统”前缀,因为TMonitor名称与表单单元中的类型冲突。另一种选择是使用全局和函数。)使用类帮助程序,您可以使用此选项。但不能与旧版本一起使用。但我建议仅在XE5中使用TMonitor。因为它比TRTLCriticalSection慢很多
至少您可以调用windows API关键部分锁列表还需要以某种方式排序,并通过二进制搜索完成“定位”,以提高性能。@Ken Bourassa:是的,还有很多改进的余地。不过,我们的目的只是展示如何使用Delphi 6实现c#中使用的类似构造。Delphi 2009引入了锁定任何对象的功能-请参见“为什么在Delphi 2009中TObject的大小翻了一番?”是的,我后来了解到了这一点,但是这个问题已经被编辑成了Delphi6,所以我没有费心更新我的答案,只是为了把它放回头版。不过我应该留下评论。但是,我要指出,我反对那篇文章中的观点。锁定任何对象的能力都不是一件好事,如果不知道自己在做什么,很容易导致死锁。因为任何人都可以锁定任何对象,所以有时他们会锁定。最好专门分配锁定对象并使用它们。(在这方面)毫无意外
unit uLock;
interface
type
ILock = interface
['{55C05EA7-D22E-49CF-A337-9F989006D630}']
procedure UnLock;
end;
function Lock(const ASharedObj: TObject): ILock;
implementation
uses
syncobjs, classes;
type
_ILock = interface
['{BAC7CDD2-0660-4375-B673-ECFA2BA0B888}']
function SharedObj: TObject;
procedure Lock;
end;
TLock = class(TInterfacedObject, ILock, _ILock)
private
FCriticalSection: TCriticalSection;
FSharedObj: TObject;
function SharedObj: TObject;
public
constructor Create(const ASharedObj: TObject);
destructor Destroy; override;
procedure Lock;
procedure UnLock;
end;
var
Locks: IInterfaceList;
InternalLock: TCriticalSection;
function Lock(const ASharedObj: TObject): ILock;
var
I: Integer;
begin
InternalLock.Acquire;
try
//***** Does a lock exists for given Shared object
for I := 0 to Pred(Locks.Count) do
if (Locks[I] as _ILock).SharedObj = ASharedObj then
begin
Result := ILock(Locks[I]);
Break;
end;
//***** Create and add a new lock for the shared object
if not Assigned(Result) then
begin
Result := TLock.Create(ASharedObj);
Locks.Add(Result);
end;
finally
InternalLock.Release;
end;
(Result as _ILock).Lock;
end;
{ TLock }
constructor TLock.Create(const ASharedObj: TObject);
begin
inherited Create;
FSharedObj := ASharedObj;
FCriticalSection := TCriticalSection.Create;
end;
destructor TLock.Destroy;
begin
FCriticalSection.Free;
inherited Destroy;
end;
procedure TLock.Lock;
begin
FCriticalSection.Acquire;
end;
function TLock.SharedObj: TObject;
begin
Result := FSharedObj;
end;
procedure TLock.UnLock;
begin
FCriticalSection.Release;
end;
initialization
Locks := TInterfaceList.Create;
InternalLock := TCriticalSection.Create;
finalization
InternalLock.Free;
Locks := nil
end.
System.TMonitor.Enter(obj);
try
// ...
finally
System.TMonitor.Exit(obj);
end;
THelper = class helper for TObject
procedure Lock;
procedure Unlock;
end;
procedure THelper.Lock;
begin
System.TMonitor.Enter(TObject(Self));
end;
procedure THelper.Unlock;
begin
System.TMonitor.Exit(TObject(Self));
end;