0

我有多个服务处理一些文件。每个服务在处理时都必须拥有对文件的独占访问权限。不久前,我通过创建一个使用一些临时文件的全局互斥锁解决了这个问题,如下所示:

function AppLocked: boolean;
begin
  result := FileExists(GetTempDir + '__MUTEX__' + LockExt);
end;

procedure AppLock;
var
  F: TextFile;
begin
  if FileExists(GetTempDir + '__MUTEX__' + LockExt) then
    exit
  else
  try
    AssignFile(F, GetTempDir + '__MUTEX__' + LockExt);
    Rewrite(F);
    Writeln(F, DateTimeToStr(Now));
    CloseFile(F);
  except
  end;
end;

procedure AppUnLock;
begin
  if FileExists(GetTempDir + '__MUTEX__' + LockExt) then
    SysUtils.DeleteFile(GetTempDir + '__MUTEX__' + LockExt);
end;

这工作得很好,我不想修复一些有效的东西,但我只是想知道,有没有更好的解决方案?

4

2 回答 2

4

实际的 Mutex(如在 win32 Mutex 中)是首选方法。

于 2012-11-09T22:16:20.477 回答
1

如果应用程序终止并且您错过了解锁,您的解决方案就有问题。这可能发生在异常终止时。最好创建一个文件,如果应用程序终止,该文件会自动擦除。

所有的魔法都由FILE_FLAG_DELETE_ON_CLOSE完成

unit uAppLock;

interface

function AppLocked : Boolean;
function AppLock : Boolean;
procedure AppUnlock;

implementation

uses
  Windows, SysUtils, Classes;

var
  // unit global variable 
  LockFileHandle : THandle;

// function to build the filename
function GetLockFileName : string;
begin
  // You have to point out, where to get these informations
  Result := GetTempDir + '__MUTEX__' + LockExt;
end;

function AppLocked : Boolean;
begin
  Result := FileExists( GetLockFileName );
end;

function AppLock : Boolean;
var
  LFileName :       string;
  LLockFileStream : TStream;
  LInfoStream :     TStringStream;
begin
  Result := False;

  if AppLock
  then
    Exit;

  LFileName := GetLockFileName;

  // Retrieve the handle of the LockFile
  LockFileHandle := CreateFile( PChar( LFileName ), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_DELETE,
    nil, CREATE_NEW, FILE_FLAG_DELETE_ON_CLOSE or FILE_ATTRIBUTE_TEMPORARY, 0 );

  if LockFileHandle <> INVALID_HANDLE_VALUE
  then
    begin

      Result := True;

      LInfoStream     := nil;
      LLockFileStream := nil;
      try

        LInfoStream := TStringStream.Create;
        LInfoStream.WriteString( DateTimeToStr( Now ) );
        LInfoStream.Seek( 0, soFromBeginning );

        LLockFileStream := THandleStream.Create( LockFileHandle );
        LLockFileStream.CopyFrom( LInfoStream, LInfoStream.Size );

      finally
        LInfoStream.Free;
        LLockFileStream.Free;
      end;

    end;

end;

procedure AppUnlock;
begin
  // Just close the handle and the file will be deleted
  CloseHandle( LockFileHandle );
end;

end.

顺便说一句:GetTempDir看起来是一个目录,但您将它用作路径。所以最好将它重命名为GetTempPath :o)

于 2012-11-10T03:09:40.400 回答