File::Temp를 사용하여 Perl에서 잠금 파일 만들기

11511 단어 perl
Alock는 회피race conditions와 관련하여 많은 목적을 달성할 수 있습니다. 이 기사에서는 Perl의 내장File::Temp 모듈을 사용하여 잠금을 구현하는 방법을 살펴보겠습니다.

문제



다음과 같이 사용되는 "duckduckperl"이라는 프로그램을 작성할 것입니다.

usage: duckduckperl [retrieve] [print]
retrieve 명령은 "perl"이라는 단어에 대한 DuckDuckGo 검색의 HTML을 검색하여 $HOME/duckduckperl.html 에 쓰고 이미 있는 경우 이 파일을 덮어씁니다.
print 명령은 $HOME/duckduckperl.html 의 내용을 인쇄합니다.

잠재적 경쟁 조건이 있는 프로그램 버전은 다음과 같습니다.

#!/usr/bin/env perl

use strict;
use warnings;

my $OUTPUT_FILE = "$ENV{HOME}/duckduckperl.html";

my $USAGE = 'usage: duckduckperl [retrieve] [print]' . "\n";

(@ARGV == 1) or die $USAGE;

my $ARG = $ARGV[0];

if    ($ARG eq 'retrieve') { retrieve_html() }
elsif ($ARG eq 'print'   ) { print_html()    }
else                       { die $USAGE      }

sub retrieve_html {

    my $html = `curl --silent https://duckduckgo.com/?q=perl`;

    unless ($? == 0) {
        die "duckduckperl: curl command exited with status $?\n";
    }

    open my $fh, '>', $OUTPUT_FILE
      or die "duckduckperl: error: cannot open $OUTPUT_FILE: $!\n";

    print $fh $html;

    close $fh;
}

sub print_html {

    -f $OUTPUT_FILE
      or die "duckduckperl: error: cannot find file $OUTPUT_FILE\n";

    open my $fh, '<', $OUTPUT_FILE
      or die "duckduckperl: error: cannot open $OUTPUT_FILE: $!\n";

    my $html = <$fh>;

    close $fh;

    print $html;
}


이 코드에서 이해해야 할 중요한 유일한 부분은 &retrieve_html 서브루틴입니다. 왜냐하면 여기에서 잠재적 경쟁 조건이 발생하기 때문입니다. 이 서브루틴curl은 "perl"이라는 단어의 DuckDuckGo 검색을 나타내는 URL이며 실패할 경우 죽습니다. curl 명령이 성공하면 출력된 HTML$HOME/duckduckperl.html을 작성하여 파일에 이미 있는 모든 데이터를 덮어씁니다.
duckduckperl retrieve를 두 번 호출하고 (네트워크 관련) 이유가 무엇이든 두 번째 인스턴스가 먼저 완료된다고 상상해 보십시오. duckduckperl print 호출로 이동하면 예상하지 못한 두 번째 호출 대신 첫 번째 호출의 출력을 얻게 됩니다.

해결책



이 문제를 방지하기 위해 먼저 잠금 파일의 존재를 확인하도록 작성하고&retrieve_html 잠금 파일이 있으면 계속하기 전에 삭제될 때까지 기다립니다. 잠금 파일이 없으면 HTML을 검색하고 작성하기 전에 만들고 나중에 삭제합니다. 이것은 여러duckduckperl retrieve의 인스턴스는 호출된 순서대로 종료됩니다.

Perl의 내장File::Temp 모듈은 잠금 파일을 만드는 데 유용한 기능을 제공합니다. 우리가 사용할 가장 중요한 기능은 File::Temp 객체가 소멸(가비지 수집)될 때 잠금 파일을 자동으로 삭제하는 것입니다. 이 기능은 File::Temp's OO interface을 사용하는 경우 사용할 수 있습니다.

다음은 잠금 파일을 사용하는 업데이트 버전&retrieve_html입니다.

use File::Temp;

sub retrieve_html {

    my $seconds = 0;
    while (grep /DUCKDUCKPERLLOCK$/, glob('/tmp/*')) {
        if ($seconds > 120) {
            die 'duckduckperl: error: aborting after waiting 2 minutes for lock file to be deleted' . "\n";
        }
        sleep 1;
        $seconds++;
    }

    my $lock_fh = File::Temp->new(
        DIR      => '/tmp',
        TEMPLATE => 'XXXX',
        SUFFIX   => '.DUCKDUCKPERLLOCK',
        UNLINK   => 1
    );

    open my $fh, '>', $OUTPUT_FILE
      or die "duckduckperl: error: cannot open $OUTPUT_FILE: $!\n";

    my $html = `curl --silent https://duckduckgo.com/?q=perl`;

    unless ($? == 0) {
        die "duckduckperl: curl command exited with status $?\n";
    }

    print $fh $html;

    close $fh;
}


서브루틴의 첫 번째 부분은 regex /tmp 와 일치하는 /DUCKDUCKPERLLOCK$/ 디렉토리의 파일인 잠금 파일을 확인합니다. 이 파일이 있으면 프로그램을 포기하고 종료하기 전에 다음 2분 동안 1초마다 파일이 삭제되었는지 확인합니다. 잠금 파일이 없으면 File::Temp::new 을 사용하여 만듭니다.

4가지 옵션으로 File::Temp 개체를 구성합니다. DIR 옵션은 파일을 저장할 디렉토리를 지정합니다. TEMPLATE 옵션은 파일 이름 지정에 사용할 템플릿을 지정합니다. X 는 File::Temp가 생성하는 파일이 고유한 이름을 갖도록 보장하기 위해 채울 임의의 문자를 나타냅니다. SUFFIX 옵션은 파일 이름에 .DUCKDUCKPERLLOCK로 설정한 접미사를 부여합니다. 잠금 파일의 존재 여부를 확인할 때 이 접미사를 사용하여 잠금 파일을 식별합니다. 마지막으로 UNLINK 옵션은 File::Temp 개체가 소멸(가비지 수집)될 때 파일을 삭제하도록 지정합니다. 편리하게도 curl 명령이 실패하고 프로그램이 종료되더라도 File::Temp 객체는 여전히 파괴되고 잠금 파일은 삭제됩니다.
&retrieve_html 의 이 버전을 사용하면 duckduckperl retrieve 의 여러 인스턴스가 호출된 순서대로 종료된다는 것을 알고 안심할 수 있습니다.

좋은 웹페이지 즐겨찾기