作者: dune
日時: 2004/2/13(01:14)
極悪です。

Zazel さんの [TSperl:316] Re: flockの使い方? から
>>> 自分の環境で flock が使えるかどうか確かめるため、下のような
>>> スクリプトを書いて試してみました:
>> 
>> SolarisのC言語ライブラリにはflock()がありませんから
>> fcntl()ベースで動くはずなので、それなら予想された動きです。
>> 
>> # 同じプロセス上で複数回のwrite lockは素通りするはず。
>
>Cだとflock()でも同じプロセス上ではブロックされないので、
>ロックを試す場合は別プロセスが確実だと思います。(forkだけもダメ)

なるほど。書き直して試したら納得のいく結果が得られました。



--^flock1.pl
#!/usr/local/bin/perl
++$|;
print qq(Content-type: text/html; charset=EUC-JP\r\n\r\n);

sub LOCK_SH{ 1 }
sub LOCK_EX{ 2 }
sub LOCK_UN{ 4 }
sub LOCK_NB{ 8 }

#my $lockmode = LOCK_EX|LOCK_NB;
my $lockmode = LOCK_EX;
my $file = "flocktest.txt";

do{ sleep 1 }until(time =~ m/9$/);
do{ 123 }until(time =~ m/0$/);

# 0 : ファイルをロック
open(FILE1,">$file");
flock(FILE1,$lockmode);
select FILE1; $| = 1;
print FILE1 time," : $$ : flock ok\n";

# 4 : ロック解除
sleep 4;
print FILE1 $@;
print FILE1 time," : $$ : unlock ok\n";
close FILE1;

select STDOUT;
print qq(<HTML><BODY><H1>$$</H1><PRE>),`cat $file`,q(</PRE></BODY></HTML>);
--$



--^flock2.pl
#!/usr/local/bin/perl
#use strict;
++$|;
print qq(Content-type: text/html; charset=EUC-JP\r\n\r\n);

sub LOCK_SH{ 1 }
sub LOCK_EX{ 2 }
sub LOCK_UN{ 4 }
sub LOCK_NB{ 8 }

#my $lockmode = LOCK_EX|LOCK_NB;
my $lockmode = LOCK_EX;
my $file = "flocktest.txt";
my $log;

do{ sleep 1 }until(time =~ m/9$/);
do{ 123 }until(time =~ m/0$/);

# 1 : ロックを試みる(たぶん失敗)
sleep 1;
eval{
    local $SIG{ALRM} = sub{ die time," : $$ : flock 1 time-out!\n"};
    alarm 1;
    open(FILE2,">>$file");
    flock(FILE2,$lockmode) or die time," : $$ : flock 1 failure!\n";
    select FILE2; $| = 1;
    print FILE2 time," : $$ : flock 1 ok?\n";
    close FILE2;
    alarm 0;
};
$log .= $@;
alarm 0;

# 2 : ロック失敗でアラームで抜けた場合
# 4 : アラームが効かずロックに成功するまで待った場合

# 5/7 : ロックを試みる(たぶん成功)
sleep 3;
eval{
    local $SIG{ALRM} = sub{ die time," : $$ : flock 2 time-out!\n"};
    alarm 1;
    open(FILE2,">>$file");
    flock(FILE2,$lockmode) or die time," : $$ : flock 2 failure!\n";
    select FILE2; $| = 1;
    print FILE2 time," : $$ : flock 2 ok?\n";
    close FILE2;
    alarm 0;
};
$log .= $@;
alarm 0;

# 失敗したときのメッセージ
open(FILE2,">>$file");
select FILE2;
print FILE2 $log;
close FILE2;

select STDOUT;
print qq(<HTML><BODY><H1>$$</H1><PRE>),`cat $file`,q(</PRE></BODY></HTML>);
--$



flock1.pl と flock2.pl をよーいドンで動かして、でき上がった
flocktest.txt というファイルの中身を確認します。 

alarm がない Windows 2000 では、flock2(536) は 
flock1(2092) がロックを解除するのを待つので

--^flocktest.txt
1076601430 : 2092 : flock ok
1076601434 : 2092 : unlock ok
1076601434 : 536 : flock 1 ok?
1076601437 : 536 : flock 2 ok?
--$

sun4-solaris(@nifty)では、alarm が効いて flock1(17946) の
ロック解除を待たずに flock2(23711) の処理が進むので

--^
1076601370 : 17946 : flock ok
1076601374 : 17946 : unlock ok
1076601375 : 23711 : flock 2 ok?
1076601372 : 23711 : flock 1 time-out!
--$

という結果になりました。flock はちゃんと効いていることがわか
りました。ありがとうございました。
-- 
極悪, FZH01112 at nifty.com
http://hpcgi1.nifty.com/dune/gwiki.pl?