14

Delphi でマルチスレッド アプリケーションを作成していて、共有リソースを保護するために何かを使用する必要があります。

C# では、「lock」キーワードを使用します。

private someMethod() {
    lock(mySharedObj) {
        //...do something with mySharedObj
    }
}

Delphi では、似たようなものを見つけることができませんでした。TThread.Synchronize(someMethod) メソッドだけを見つけました。これは、メイン VCL スレッドで someMethod を呼び出すことによって潜在的な競合を防ぎますが、それはまさに私がやりたいことではありません....

編集:Delphi 6を使用しています

4

5 に答える 5

17

(残念ながら)Delphi 6 では任意のオブジェクトをロックできないため(2009 年以降の最新バージョンではロックできますが)、別のロック オブジェクト(通常はクリティカル セクション)が必要です。

TCriticalSection (注: ドキュメントは FreePascal のものですが、Delphi にも存在します):

コード例:

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;
于 2010-06-11T13:26:04.247 に答える
11

Delphi 6 には、これに相当するものはありません。Delphi 2009 では、これらのSystem.TMonitorメソッドを使用して、任意のオブジェクトのロックを取得できます。

System.TMonitor.Enter(obj);
try
  // ...
finally
  System.TMonitor.Exit(obj);
end;

(TMonitor 名が Forms ユニットのタイプと競合するため、"System" プレフィックスが必要です。代わりに、グローバル関数MonitorEnterMonitorExit関数を使用することもできます。)

于 2010-06-11T14:34:27.627 に答える
3

C# ほど簡単ではありませんが、次のようにするとうまくいくかもしれません。

  with Lock(mySharedObj) do
  begin
    //...do something with mySharedObj
    UnLock;
  end;

手短に

  • 保護したいすべてのインスタンスのリストが保持されます。
  • 2 番目のスレッドが を呼び出すとLock(mySharedObj)、内部リストで既存のロックが検索されます。既存のロックが見つからない場合は、新しいロックが作成されます。別のスレッドがまだロックを保持している場合、新しいスレッドはブロックされます。
  • これが必要なのは、メソッド呼び出しの最後Unlockに ILock インスタンスへの参照のみがスコープ外になるかどうかを確認できないためです。(可能であれば、削除できます)。LockUnlock

この設計では、アプリケーションが終了するまで解放されることなく、保護するすべてのオブジェクト インスタンスに対して 1 つの TLock が作成されることに注意してください。
これは考慮に入れることができますが、_AddRef と _Release をいじる必要があります。


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.
于 2010-06-11T13:45:23.593 に答える
1

前述のように、ローカル スコープ外で呼び出されず、他のロックを取得しない短いコードの場合は、 を介してクリティカル セクションを使用できます。SyncObjs.TCriticalSectionより
長く/より複雑なコードを使用する場合はSyncObjs.TMutex、待機可能です (タイムアウトあり)。所有しているスレッドが死んでも停止せず、別のプロセスと名前で共有できます。
これらのラッパーを使用すると、同期レイヤーへの変更が容易になります。

すべての場合において、ここでドラゴンに注意してください: TMutex delphi の WaitFor 関数と win32 API の同等の関数の違いに対する私の答え

于 2010-06-11T13:35:41.450 に答える
0

クラスヘルパーを使用すると、これを使用できます。ただし、古いバージョンでは動作しません。ただし、TMonitor は XE5 でのみ使用することをお勧めします。TRTLCriticalSection よりもかなり遅いためです。

http://www.delphitools.info/2013/06/06/tmonitor-vs-trtlcriticalsection/

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;
于 2013-11-04T10:32:03.383 に答える