문제

Perl에서 파일에 잠금을 만드는 가장 좋은 방법은 무엇입니까?

파일을 모아 두는 것이 최선입니까, 아니면 잠금 파일을 생성하여 잠금을 설정하고 잠금 파일에 대한 잠금을 확인하는 것이 가장 좋습니까?

도움이 되었습니까?

해결책

무리를 사용하게 된 경우 이를 수행하는 몇 가지 코드는 다음과 같습니다.

use Fcntl ':flock'; # Import LOCK_* constants

# We will use this file path in error messages and function calls.
# Don't type it out more than once in your code.  Use a variable.
my $file = '/path/to/some/file';

# Open the file for appending.  Note the file path is quoted
# in the error message.  This helps debug situations where you
# have a stray space at the start or end of the path.
open(my $fh, '>>', $file) or die "Could not open '$file' - $!";

# Get exclusive lock (will block until it does)
flock($fh, LOCK_EX) or die "Could not lock '$file' - $!";

# Do something with the file here...

# Do NOT use flock() to unlock the file if you wrote to the
# file in the "do something" section above.  This could create
# a race condition.  The close() call below will unlock the
# file for you, but only after writing any buffered data.

# In a world of buffered i/o, some or all of your data may not 
# be written until close() completes.  Always, always, ALWAYS 
# check the return value of close() if you wrote to the file!
close($fh) or die "Could not write '$file' - $!";

유용한 링크:

추가된 질문에 대한 응답으로 파일에 잠금을 설정하거나 파일이 잠겨 있을 때마다 '잠금'이라고 부르는 파일을 만들고 더 이상 잠겨 있지 않으면 삭제한다고 말하고 싶습니다. 그런 다음 프로그램이 이를 준수하는지 확인하십시오. 그 의미론).

다른 팁

다른 답변은 Perl 플록 잠금을 꽤 잘 다루고 있지만 많은 Unix/Linux 시스템에는 실제로 두 개의 독립적인 잠금 시스템이 있습니다.BSD Flock() 및 POSIX fcntl() 기반 잠금.

Perl을 빌드할 때 구성할 특별한 옵션을 제공하지 않는 한 해당 무리는 가능한 경우 Flock()을 사용합니다.이는 일반적으로 문제가 없으며 응용 프로그램 내에서 잠금이 필요한 경우(단일 시스템에서 실행) 아마도 원하는 것일 것입니다.그러나 때로는 fcntl() 잠금을 사용하는 다른 애플리케이션(예: 많은 시스템에서 Sendmail)과 상호 작용해야 하거나 NFS 마운트 파일 시스템 전체에서 파일 잠금을 수행해야 할 수도 있습니다.

그런 경우에는 다음을 살펴보는 것이 좋습니다. 파일::FcntlLock 또는 파일::lockf.순수 Perl에서 fcntl() 기반 잠금을 수행하는 것도 가능합니다(일부 복잡하고 이식 불가능한 pack() 비트 사용).

Flock/fcntl/lockf 차이점에 대한 간략한 개요:

lockf는 거의 항상 fcntl 위에 구현되며 파일 수준 잠금만 갖습니다.fcntl을 사용하여 구현하는 경우 아래 제한 사항이 lockf에도 적용됩니다.

fcntl은 NFS를 통한 범위 수준 잠금(파일 내)과 네트워크 잠금을 제공하지만 잠금은 fork() 이후 하위 프로세스에 상속되지 않습니다.많은 시스템에서 공유 잠금을 요청하려면 파일 핸들을 읽기 전용으로 열어야 하고, 배타적 잠금을 요청하려면 읽기-쓰기가 가능해야 합니다.

Flock에는 파일 수준 잠금만 있으며 잠금은 단일 시스템 내에서만 가능합니다(NFS 마운트 파일을 잠글 수 있지만 로컬 프로세스만 잠금을 볼 수 있습니다).잠금은 자식에게 상속됩니다(파일 설명자가 닫히지 않았다고 가정).

때때로 (SYSV 시스템) 무리는 lockf 또는 fcntl을 사용하여 에뮬레이션됩니다.일부 BSD 시스템에서는 lockf가 Flock을 사용하여 에뮬레이트됩니다.일반적으로 이러한 종류의 에뮬레이션은 제대로 작동하지 않으므로 이를 피하는 것이 좋습니다.

CPAN을 구출합니다: IO::잠긴 파일.

Ryan P는 다음과 같이 썼습니다.

이 경우 파일이 다시 열리는 동안 짧은 시간 동안 파일이 실제로 잠금 해제됩니다.

그러니 그렇게 하지 마세요.대신에, open 읽기/쓰기용 파일:

open my $fh, '+<', 'test.dat'
    or die "Couldn’t open test.dat: $!\n";

카운터를 작성할 준비가 되면 seek 파일의 시작 부분으로 돌아갑니다.참고로 그렇게 하시면 truncate 직전 close, 새 내용이 이전 내용보다 짧은 경우 파일에 후행 쓰레기가 남지 않도록 합니다.(보통 파일의 현재 위치는 끝이므로 그냥 쓸 수 있습니다. truncate $fh, tell $fh.)

또한 제가 세 가지 인수를 사용했다는 점에 유의하세요. open 그리고 어휘 파일 핸들도 확인했으며 작업 성공 여부도 확인했습니다.전역 파일 핸들(전역 변수가 잘못되었나요? 음, 그렇죠?)과 마법의 두 인수를 피하세요. open (이는 Perl 코드에서 악용 가능한 많은 버그의 원인이 되었습니다) 항상 테스트해야 합니다. open성공해요.

어휘 변수를 파일 처리기로 사용하여 이것을 표시하는 것이 훨씬 낫다고 생각합니다 및 오류 처리.또한 모든 운영 체제에서 올바른 숫자가 아닐 수 있는 매직 넘버 2를 하드 코딩하는 것보다 Fcntl 모듈의 상수를 사용하는 것이 더 좋습니다.

    use Fcntl ':flock'; # import LOCK_* constants

    # open the file for appending
    open (my $fh, '>>', 'test.dat') or die $!;

    # try to lock the file exclusively, will wait till you get the lock
    flock($fh, LOCK_EX);

    # do something with the file here (print to it in our case)

    # actually you should not unlock the file
    # close the file will unlock it
    close($fh) or warn "Could not close file $!";

전체 내용을 확인하세요 무리의 문서화 그리고 파일 잠금 튜토리얼 PerlMonks에서는 이전 스타일의 파일 핸들 사용을 사용하더라도 마찬가지입니다.

사실 나는 보통 close ()에서 오류 처리를 건너 뜁니다. 어쨌든 실패하면 할 수 있는 일이 많습니다.

잠글 항목과 관련하여 단일 파일에서 작업하는 경우 해당 파일을 잠급니다.한 번에 여러 파일을 잠가야 하는 경우(교착 상태를 방지하려면) 잠그는 파일 하나를 선택하는 것이 좋습니다.그것이 실제로 잠그는 데 필요한 여러 파일 중 하나인지 아니면 잠금 목적으로만 생성한 별도의 파일인지는 중요하지 않습니다.

다음을 사용하는 것을 고려해 보셨나요? LockFile::간단한 모듈?이는 이미 대부분의 작업을 수행합니다.

과거 경험에 따르면 사용하기가 매우 쉽고 튼튼하다는 것을 알았습니다.

use strict;

use Fcntl ':flock'; # Import LOCK_* constants

# We will use this file path in error messages and function calls.
# Don't type it out more than once in your code.  Use a variable.
my $file = '/path/to/some/file';

# Open the file for appending.  Note the file path is in quoted
# in the error message.  This helps debug situations where you
# have a stray space at the start or end of the path.
open(my $fh, '>>', $file) or die "Could not open '$file' - $!";

# Get exclusive lock (will block until it does)
flock($fh, LOCK_EX);


# Do something with the file here...


# Do NOT use flock() to unlock the file if you wrote to the
# file in the "do something" section above.  This could create
# a race condition.  The close() call below will unlock it
# for you, but only after writing any buffered data.

# In a world of buffered i/o, some or all of your data will not 
# be written until close() completes.  Always, always, ALWAYS 
# check the return value on close()!
close($fh) or die "Could not write '$file' - $!";

이 질문의 목표는 여러 스크립트의 데이터 저장소로 사용되는 파일을 잠그는 것이었습니다.결국 나는 Chris가 작성한 다음과 유사한 코드를 사용했습니다.

open (FILE, '>>', test.dat') ; # open the file 
flock FILE, 2; # try to lock the file 
# do something with the file here 
close(FILE); # close the file

그의 예에서는 close(FILE)가 이 작업도 수행하므로 FILE, 8 무리를 제거했습니다.실제 문제는 스크립트가 시작될 때 현재 카운터를 유지해야 하고, 끝날 때 카운터를 업데이트해야 한다는 것입니다.Perl이 파일을 읽는 데 문제가 있는 부분은 다음과 같습니다.

 open (FILE, '<', test.dat');
 flock FILE, 2;

이제 결과를 작성하고 싶습니다. 파일을 덮어쓰고 싶으므로 다시 열고 잘라야 하며 결과는 다음과 같습니다.

 open (FILE, '>', test.dat'); #single arrow truncates double appends
 flock FILE, 2;

이 경우 파일이 다시 열리는 동안 짧은 시간 동안 파일이 실제로 잠금 해제됩니다.이는 외부 잠금 파일의 경우를 보여줍니다.파일의 컨텍스트를 변경하려면 잠금 파일을 사용하십시오.수정된 코드:

open (LOCK_FILE, '<', test.dat.lock') or die "Could not obtain lock";
flock LOCK_FILE, 2;
open (FILE, '<', test.dat') or die "Could not open file";
# read file
# ...
open (FILE, '>', test.dat') or die "Could not reopen file";
#write file
close (FILE);
close (LOCK_FILE);

다음에서 개발됨 http://metacpan.org/pod/File::FcntlLock

use Fcntl qw(:DEFAULT :flock :seek :Fcompat);
use File::FcntlLock;
sub acquire_lock {
  my $fn = shift;
  my $justPrint = shift || 0;
  confess "Too many args" if defined shift;
  confess "Not enough args" if !defined $justPrint;

  my $rv = TRUE;
  my $fh;
  sysopen($fh, $fn, O_RDWR | O_CREAT) or LOGDIE "failed to open: $fn: $!";
  $fh->autoflush(1);
  ALWAYS "acquiring lock: $fn";
  my $fs = new File::FcntlLock;
  $fs->l_type( F_WRLCK );
  $fs->l_whence( SEEK_SET );
  $fs->l_start( 0 );
  $fs->lock( $fh, F_SETLKW ) or LOGDIE  "failed to get write lock: $fn:" . $fs->error;
  my $num = <$fh> || 0;
  return ($fh, $num);
}

sub release_lock {
  my $fn = shift;
  my $fh = shift;
  my $num = shift;
  my $justPrint = shift || 0;

  seek($fh, 0, SEEK_SET) or LOGDIE "seek failed: $fn: $!";
  print $fh "$num\n" or LOGDIE "write failed: $fn: $!";
  truncate($fh, tell($fh)) or LOGDIE "truncate failed: $fn: $!";
  my $fs = new File::FcntlLock;
  $fs->l_type(F_UNLCK);
  ALWAYS "releasing lock: $fn";
  $fs->lock( $fh, F_SETLK ) or LOGDIE "unlock failed: $fn: " . $fs->error;
  close($fh) or LOGDIE "close failed: $fn: $!";
}

자물쇠에 대한 하나의 대안 파일 접근 방식은 잠금을 사용하는 것입니다 소켓.보다 잠금::소켓 그러한 구현을 위해 CPAN에 대해 알아보세요.사용법은 다음과 같이 간단합니다.

use Lock::Socket qw/lock_socket/;
my $lock = lock_socket(5197); # raises exception if lock already taken

소켓을 사용하면 몇 가지 장점이 있습니다.

  • (운영 체제를 통해) 두 응용 프로그램이 동일한 잠금을 유지하지 않도록 보장합니다.경쟁 조건이 없습니다.
  • 프로세스가 종료될 때 깔끔하게 정리되도록(운영 체제를 통해) 보장되므로 처리해야 할 오래된 잠금이 없습니다.
  • Perl이 실행되는 모든 것에서 잘 지원되는 기능에 의존합니다.예를 들어, Win32의 Flock(2) 지원에는 문제가 없습니다.

물론 명백한 단점은 잠금 네임스페이스가 전역적이라는 것입니다.다른 프로세스가 필요한 포트를 잠그기로 결정하면 일종의 서비스 거부가 발생할 수 있습니다.

[폭로:나는 앞서 언급한 모듈의 작성자입니다.]

사용 대군 루크.

편집하다: 이것 좋은 설명이네요.

Flock은 Unix 스타일 파일 잠금을 생성하며 Perl이 실행되는 대부분의 OS에서 사용할 수 있습니다.그러나 무리의 자물쇠는 단지 권고사항일 뿐입니다.

편집하다:무리는 휴대 가능하다는 점을 강조했습니다.

하나의 자물쇠로 읽고 쓰는 솔루션은 다음과 같습니다.

open (TST,"+< readwrite_test.txt") or die "Cannot open file\n$!";
flock(TST, LOCK_EX);
# Read the file:
@LINES=<TST>;
# Wipe the file:
seek(TST, 0, 0); truncate(TST, 0);
# Do something with the contents here:
push @LINES,"grappig, he!\n";
$LINES[3]="Gekke henkie!\n";
# Write the file:
foreach $l (@LINES)
{
   print TST $l;
}
close(TST) or die "Cannot close file\n$!";
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top