燈明ブログ

現状は小池啓仁の応援ブログ

Perlでのファイルロックについて

Perlでのファイルロックでは、普通、flock関数を使用します。
flock関数の第1引数にはファイルハンドルを指定し、第2引数には以下のいずれかの値を指定します。
尚、 LOCK_SHやLOCK_EX等を使用する場合は、『use Fcntl ':flock';』宣言が必要です。

  • 1(LOCK_SH):共有ロック(ブロキングモード)
  • 2(LOCK_EX):排他ロック(ブロキングモード)
  • 5(LOCK_SH | LOCK_NB):共有ロック(ノンブロキングモード)
  • 6(LOCK_EX | LOCK_NB):排他ロック(ノンブロキングモード)
  • 8(LOCK_UN):ロック解除(closeでもロック解除される)


1は、本処理がファイルに対して他のプロセスの書込をロックし、本処理終了まで他のプロセスを待たせます。
2は、本処理がファイルに対して他のプロセスの書込読込をロックし、本処理終了まで他のプロセスを待たせます。
5は、本処理がファイルに対して他のプロセスの書込をロックし、他のプロセスは即時復帰(リターン値0)する。
6は、本処理がファイルに対して他のプロセスの書込読込をロックし、他のプロセスは即時復帰(リターン値0)する。


尚、本ロック処理は、同ファイルに対してflock関数を使っているプロセス同士で有効で、flock関数を使っていないプロセスでは無効です。このようなロックをアドバイザリーロックと呼ぶらしい…。

◆ 2のサンプル

use strict;
use warnings;
use Fcntl ':flock';

my $counter_file = 'counter.dat';

open my $fh, '+<', $counter_file or die "$!:($counter_file)"; 
flock $fh, LOCK_EX;      # 排他ロックをかける
print "---ロック中---\n";# デバック文
my $counter = <$fh>;     # カウント値を読み込む
$counter++;              # カウントアップ
seek $fh, 0, 0;          # 書き込み位置をファイルの先頭に移動
print $fh $counter;      # カウント値を書き込む
sleep 5;                 # デバックで5秒待つ
close $fh;               # 排他ロックの解除する

◆ 5のサンプル

use strict;
use warnings;
use Fcntl ':flock';

my $retry = 3; # リトライ回数(3回)
my $wait = 1;  # リトライ時間(1分)

my $counter_file = 'counter.dat';

open my $fh, '+<', $counter_file or die "$!:($counter_file)";

my $locked = 0; # 1でロックオン
for (my $i = 0; $i < $retry; $i++) {
  if (flock $fh, LOCK_EX|LOCK_NB) {
    print "---ロック中---\n";
    $locked = 1;
    last;
  }
  sleep $wait;
}
if ($locked != 1) {
   die '他のプロセスがロック中で処理できず!';
}

my $counter = <$fh>;
$counter++;
seek $fh, 0, 0;
print $fh $counter;
sleep 4; # テストSleep
close $fh;