#navi_header|Perl| * Perlでのファイルのロック方法メモ - 基本は '' flock '' 。但し、ここで使用するLOCK_SH, LOCK_EX, LOCK_UN, LOCK_NBは、 use Fcntl(:flock); or use Fcntl(:DEAFULT :flock); しておく必要がある。FcntlはシステムのCライブラリのfcntl.hをh2xsで取り込んで利用できるようにしてくれたモジュール。基本的に#defineされたものが取り込まれている。 - '' :DEFAULT '' を指定すると、F_&pre(){*}, O_&pre(){*} 系列をデフォルトでEXPORTしてくれる。他に '' :flock, :seek, :mode '' なども指定できる。 - flockはファイルハンドルのみを扱える。ネットワークソケットなど、Cの世界で言うところのファイルディスクリプタを生で取り扱うシーンでは、Cと同様に '' fcntl '' を使用する。 - NFSを除くファイルシステムでのファイルのロックでは、flockで充当する。NFSにおいてはfcntlを行う必要があるらしい。これはLinuxのCレイヤーの現象らしい。 以下、参考。 - Linux Man Page -- http://www.linux.or.jp/JM/html/LDP_man-pages/man2/flock.2.html -- http://www.linux.or.jp/JM/html/LDP_man-pages/man2/fcntl.2.html - perldoc -- flock: http://perldoc.perl.org/functions/flock.html -- Core Module, Fcntl: http://perldoc.perl.org/Fcntl.html -- fnctl: http://perldoc.perl.org/functions/fcntl.html * Perlのflockは"advisory"ロックである点に要注意 flockのperldocにもしっかり太字で記載されていますが、Perlのflockは"advisory"ロックです。つまり、flockを使用しているもの同士であればロックは機能しますが、flockを使用せずに読み書きを行うプロセスに対しては機能しません。 実際、下のコードピースを使うと明らかです。コードピース同士でのロックは、同じflockを使用しているので、排他ロックは「その通りに」動作します。(戻り値がそのように見えます。) しかしechoやviなどの読み書きプロセスと同時に動かして実験してみると、Perl側でLOCK_EXをかけているのに、echoシェルリダイレクトでファイルに書き込めますし、viの編集も何の問題もなく上書き保存可能です。 Perl同士でしか読み書きしないCGIのロックファイルについては有効ですが、別のプログラミング言語やプログラムなどで同時に読み書きするときは、Perlのflockが機能しない場合も有る点に注意が必要です。 * コードピース(LOCK_{SH|EX|UN|NB}の実験) 標準入力からLOCK_*を受付け、コマンドラインで指定されたファイルに対してflock操作を行う。 異なる端末から二つ以上立ち上げていろいろ遊んでみる事を想定。 ここではローカルファイルシステム上のファイルをロック・アンロックする実験を行いたい為、flockで問題ない。 ファイルロックの他に、標準入力からのreadlineやswitch構文、他参考リンク。 - IO::File : http://perldoc.perl.org/IO/File.html - readline(), <> : http://perldoc.perl.org/functions/readline.html - switch() : http://perldoc.perl.org/Switch.html - http://blog.livedoor.jp/dankogai/archives/50780781.html #!/usr/bin/perl use strict; use warnings; use Data::Dumper; use Switch; use Fcntl qw(:flock); if(@ARGV < 1) { die "usage: $0 \n"; } my $file = $ARGV[0]; my $lock_nb = 0; if(! -e $file ) { die "$file is not exist!\n"; } print "Lock target file is '$file'.\n"; ## 通常のファイルハンドルを使用した書き方 # open my $fh, "<$file" or die "Open failure '$file'.($!)\n"; ## IO::Fileを用いた書き方 my $fh = IO::File->new("+<$file"); # エラーハンドリングは$fhがdefinedか否かで判別する。 # エラーコードはシステムのerrnoなので $! を参照する。 die "Open file failure '$file' ($!).\n" unless defined($fh); sub help { my ($msg) = @_; print "unrecognized statement: $msg\n"; print "statement are: LOCK_SH, LOCK_EX, LOCK_UN, LOCK_NB.\n"; print "(LOCK_NB switches LOCK_NB mode.)\n"; } my $line = undef; for(;;) { undef $!; unless (defined($line = )) { # if reached EOF, break loop. die $! if $!; last; } if($line !~ /^([A-Z_]+)/ ) { &help($line); next; } switch($1) { my $ret = 0; case "LOCK_SH" { $ret = flock($fh, LOCK_SH | $lock_nb); print "LOCK_SH results $ret.\n"; } case "LOCK_EX" { $ret = flock($fh, LOCK_EX | $lock_nb); print "LOCK_EX results $ret.\n"; } case "LOCK_UN" { $ret = flock($fh, LOCK_UN); print "LOCK_UN results $ret.\n"; } case "LOCK_NB" { $lock_nb = ($lock_nb) ? 0 : LOCK_NB; print "LOCK_NB is ". (($lock_nb) ? "ON" : "OFF") . ".\n"; } else { &help($1); } } } # open my $fh の場合 #close $fh; # IO::File の場合 $fh->close; #navi_footer|Perl|