ルモーリン
ホーム 更新 Perl Sample サービス 雑談 鉄ゲタ Linux リンク 連絡先

Perlサンプル15 ファイルアクセスの競合整理

2020-01-21

内容

例えばファイルといった1つの資源をCGIのように非同期に呼ばれると競合して誤動作しますよね。 昔のホームページですとアクセスカウンタをファイルで管理していて、競合を整理できずにカウント値が吹っ飛ぶとかありました(老眼)。 そういう「同時にアクセスした際に一瞬でも先着したほうを優先、後着は先着の処理が全部終わるまで待たせる」処理を書いてみました。

実行サンプル

このページを2個のタブでそれぞれ表示させてから、順にリンクをクリックしてみてください。 先着のほうが1秒ずつ「待機中」を表示して10秒待って終了します。 後着は「ロック開始」から進まずに先着が終了後に再開します。

サンプル4

実行結果

 サンプル4の実行結果

処理開始
只今の日時は2020-01-21 20:53:10です。
ファイルオープン
ロック開始
ロック完了
待機中(0)
待機中(1)
待機中(2)
待機中(3)
待機中(4)
待機中(5)
待機中(6)
待機中(7)
待機中(8)
待機中(9)
アンロック開始
アンロック完了
ファイルクローズ

元のページに戻る

コード

#/usr/bin/perl

use utf8;
use strict;
use warnings;

use DateTime;
use Fcntl qw(:flock);

binmode STDOUT, ":utf8 :crlf";

$| = 1;

print <<EOF;
Content-Type: text/html;charset=UTF-8

<html>
<head>
<title>サンプル4の実行結果</title>
</head>
<body>
<p>
サンプル4の実行結果<br />
</p>
<p>
EOF

print "処理開始<br />\n";
my $dt = DateTime->now(time_zone => "local");
print $dt->strftime("只今の日時は%F %Tです。<br />\n");

print "ファイルオープン<br />\n";
open my $single_fh, ">", "sample4.single";
print "ロック開始<br />\n";
if (flock $single_fh, LOCK_EX) {
	print "ロック完了<br />\n";
	for (my $i = 0; $i < 10; $i++) {
		print "待機中($i)<br />\n";
		sleep 1;
	}

	print "アンロック開始<br />\n";
	flock $single_fh, LOCK_UN;
	print "アンロック完了<br />\n";
}
close $single_fh;
print "ファイルクローズ<br />\n";

print <<EOF;
</p>
<p>
<a href="../sample/0f_perlsample_015.html">元のページに戻る</a><br />
</p>
</body>
</html>
EOF

解説

flockで1つのファイルをロックして競合を整理しますので、こちらをご覧ください。
Perlの組み込み関数 flock の翻訳 - perldoc.jp