トップページ⇒php
981コメント337KB

【Perl】ファイルロック(排他処理)について語ろう

■ このスレッドは過去ログ倉庫に格納されています
0001nobodyさん02/06/23 10:18ID:eY2l+Gw1
どんな環境でも使えて、軽くて、頑丈なロックを考えようじゃありません
0792nobodyさん2005/03/30(水) 19:01:47ID:???
伝書鳩 (ry
0793nobodyさん2005/03/31(木) 04:46:07ID:???
>>792
それだ!

To: [email protected]
Subject: Lock

user=xxxx
pass=xxxx
timeout=60
lock-id=1
=======
↓
登録してある住所にlock-id確認コードを郵送
↓
登録ページからlock-id確認コードを入力
07947892005/03/31(木) 09:19:53ID:???
thnx>>790
0795nobodyさん2005/04/02(土) 05:31:48ID:???
rename $0 $0.tmp
perl $0.tmp
rename $0.tmp $0

0796nobodyさん2005/04/04(月) 15:59:12ID:UmDaQFM/
>>795
すげw
0797nobodyさん2005/04/08(金) 17:32:31ID:???
ごめん、>>795のどこがすげwのか、解説してください?
0798nobodyさん2005/04/08(金) 19:48:39ID:???
自信をリネームとかできんのかな
0799nobodyさん2005/04/08(金) 21:23:04ID:???
リネームに失敗しても、他のプロセスがリネームしてるヤツがあれば実行する罠
0800nobodyさん2005/04/08(金) 23:18:53ID:???
書き込みの最中に死んだりするとデータ全部消えて無くなるな。仕方ないか。
0801nobodyさん2005/04/09(土) 19:52:50ID:???
>>800
ゆーあーばか
0802nobodyさん2005/06/06(月) 21:34:45ID:nLjgLi0T
sub create_lock {
  for ($i = 0; $i < 10; $i++) {#10回繰り返す
    return if link($0, $lock);#link関数でロックファイルが作成できれば終了
    sleep(1);#作れない場合は1秒スリープしてから再挑戦
  }
  print "BUSY";#10回以内にロックできない場合はBUSYと表示
  exit;#スクリプト終了
}

↑だとうまくいくのに、↓だとうまくいかないのは何ででしょうか?
↓ですとsleepを5回繰り返した後&error("BUSY")の処理をします。

sub create_lock {
  local($retry) = 5;
  # 1分以上古いロックは削除する
  if (-e $lockfile) {
    local($mtime) = (stat($lockfile))[9];
    if ($mtime < time - 60) {
      &unlock;
    }
  }
  while (!mkdir($lockfile, 0755)) {
    if (--$retry <= 0) {
      &error("BUSY");#5回以内にロックできない場合はBUSYと表示
    }
    sleep(1);
  }
  exit;
}
0803nobodyさん2005/06/06(月) 21:38:25ID:???
あかさたなはまやらわあかさたなはまやらわあかさたなはまやらわあかさたなはまやらわあかさたなはまやりわあかさたなはまやらわあかさたなはまやらわあかさたなはまやらを
0804nobodyさん2005/06/06(月) 23:11:37ID:pBVz6jtY
>>802
よくわからんがmkdirに成功するとwhileループを抜けてすぐ
exitするからじゃないか?

それ以外にも古いロックを削除するあたりが突っ込みどころ
ありそうだが、サブルーチンunlockがどういうものか示されて
ない以上は疑惑レベルだな。
0805nobodyさん2005/06/07(火) 11:44:43ID:Jzx4SwvB
なぜこれでロックがかかるのでしょうか?
フォルダを作って消してるだけのような気がするんですけど。
↓

&createlock();#mkdirでロックファイルを作成する
open(FILE,"+<$logfile");
 〜(処理)〜
close(FILE);
&unlock;#rmdirでロックファイルを削除する
0806nobodyさん2005/06/07(火) 12:33:20ID:???
createlock と unlock の中身がわからないとなんとも・・・。
0807nobodyさん2005/06/07(火) 15:11:06ID:???
サーバー環境によって使えたり使えなかったりする関数の一覧みたいなのって
WEBに転がってませんかね?

環境  A  B  C
flock × ○ ○
mkdir ○ ○ ○

こんな感じの一覧表みたいなのがあればいいな
0808nobodyさん2005/06/07(火) 18:06:21ID:???
>>804
802です。お答えありがとうございました。
ごめんなさい、勘違いしてました。ちゃんとロックできました。
ところで、質問ですけども、

sub create_lock {
  local($retry) = 5;
  if (-e $lockfile) {
    local($mtime) = (stat($lockfile))[9]; # ←この部分の[9]
    if ($mtime < time - 60) {
      &unlock;
    }
  }
  while (!mkdir($lockfile, 0755)) {
    if (--$retry <= 0) {
      &error("BUSY");
    }
    sleep(1);
  }
  exit;
}

↑の文章の
local($mtime) = (stat($lockfile))[9];
特に[9]の意味が分からないのですが、この文章は何を意味するのでしょうか?
0809nobodyさん2005/06/07(火) 19:19:30ID:???
>>808
statはファイルの様々な情報を長いリストにして返す関数で、その9番目の
要素であるところのファイル更新時間だけ欲しいから[9]で取り出してると
いうことだな。詳しくはperldoc -f statでもしてくれ。
0810nobodyさん2005/06/07(火) 20:02:25ID:???
>>809
ありがとうございました。理解できました。
0811nobodyさん2005/06/07(火) 20:15:05ID:???
>>809
前から疑問に思っていたんだが、
> 9番目
0から始まっているから、この場合10番目なのはみんな知っていると思うけど、9番目といってもいいのかな?
どういう言い方が正しいのか教えて。
0812nobodyさん2005/06/07(火) 20:59:09ID:???
9番目の要素(ninth element)、0番目の要素(zeroth element)でいいと思うけど、
9番の要素、0番の要素の方がすっきりする?
0813nobodyさん2005/06/07(火) 22:14:04ID:???
質問です。かの有名なperlメモで以下のように書きました。
my_flockのサブルーチンの中で、戻り値を「\%lfh」のようにリファレンスで返す理由がわかりません。どなたか教えてください

$lfh = my_flock() or die 'Busy!';
open(FILE,"+<$logfile");
chop($count = <FILE>);
$count++;
seek(FILE,0,0);
print FILE "$count\n";
close(FILE);
my_funlock($lfh);

sub my_flock {
  my %lfh = (dir => './lockdir/', basename => 'lockfile', timeout => 60, trytime => 5, @_);
  $lfh{path} = $lfh{dir} . $lfh{basename};
  for (my $i = 0; $i < $lfh{trytime}; $i++, sleep 1) {
    return \%lfh if (rename($lfh{path}, $lfh{current} = $lfh{path} . time));    
  }    # ■↑戻り値がなぜ\%lfh?
  opendir(LOCKDIR, $lfh{dir});
  my @filelist = readdir(LOCKDIR);
  closedir(LOCKDIR);
  foreach (@filelist) {
    if (/^$lfh{basename}(\d+)/) {
      return \%lfh if (time - $1 > $lfh{timeout} and rename($lfh{dir} . $_, $lfh{current} = $lfh{path} . time));
      last;    # ■↑戻り値がなぜ\%lfh?
    }
  }
  undef;
}
sub my_funlock {
  rename($_[0]->{current}, $_[0]->{path});
}
0814nobodyさん2005/06/07(火) 22:35:39ID:???
my_funlockで$lfh{current}と$lfh{path}の2つの値を使いたい
ので、この作者は(他にもいろいろ方法は考えられるがたまたま)
その2つの値が入ったハッシュのリファレンスを返すという方法
を選択した、というところだろうか。
0815nobodyさん2005/06/08(水) 00:31:21ID:HPDd28CP
>>813
戻り値無しで
if (rename($lfh{path}, $lfh{current} = $lfh{path} . time));
return;
とやっても同じ 
0816nobodyさん2005/06/08(水) 12:02:28ID:???
ここのカウンター広告ないし最高だよ。
http://www.eucaly.net/
http://www.eucaly.net/
http://www.eucaly.net/
http://www.eucaly.net/
http://www.eucaly.net/
http://www.eucaly.net/
http://www.eucaly.net/
http://www.eucaly.net/
http://www.eucaly.net/
http://www.eucaly.net/
0817nobodyさん2005/06/08(水) 12:12:58ID:???
>>815
違うような・・・
0818nobodyさん2005/06/08(水) 13:04:42ID:???
>>814
お答えありがとうございました。
何かの弾みで「./lockdir/lockfile」の名前が変わってしまうことってありますか?
その場合ってエラーを返すしかないのでしょうか?
0819nobodyさん2005/07/02(土) 23:42:28ID:MoVRWRYG
PHPで掲示板のログファイルを読み込んで配列に入れるのに
file()を使ってたんですが、これはロックされてないですよね?

fopenしてflockに変更した方がいいですか?
0820nobodyさん2005/07/03(日) 19:24:42ID:???
>>819
スレタイを声を出して100回読んでみなさい。
0821nobodyさん2005/07/06(水) 15:38:22ID:???
ファイルロック(排他処理)について語ろう
0822nobodyさん2005/07/06(水) 20:01:43ID:???
ファイルロック(排他処理)について語ろう
0823nobodyさん2005/07/07(木) 11:51:39ID:???
file関数は読み込みしかしないからロックも何もない
0824nobodyさん2005/07/11(月) 12:06:06ID:LOhIsGf7
open LOCK, ">hogehoge";
flock LOCK, 2;
処理;


↑のようにLOCKをしっぱなしで、closeをしないとどうなりますか?
一連の処理が終了したら、LOCKは自動解除されるんでしょうか?
0825nobodyさん2005/07/11(月) 15:42:12ID:???
PGが終了すればファイルハンドルは閉じられる。
0826nobodyさん2005/07/11(月) 16:23:12ID:???
ファイルロック難しいお
0827nobodyさん2005/09/29(木) 15:27:47ID:6eWvRT5D
エクセルでテンポラリがリネームに失敗するのは排他処理に失敗したこと
による可能性はありますか?
0828nobodyさん2005/09/30(金) 17:50:44ID:???
ロック用ファイル1に時刻書き込み
↓
ロックファイル1に時刻がなかったらロック用ファイル2を開いてロック(あったら待機)
↓
一時ファイルに書き込み
↓
読み込み用ファイルに内容をコピー
↓
ロック用ファイル2を閉じる
↓
ロック用ファイル1を空にする

最強、破損なし。
時刻は異常があった時に現在時刻と比較して無限待機させない用。
0829nobodyさん2005/09/30(金) 18:31:16ID:???
>>828
「1に時刻書き込み」してから「1に時刻がなかったら」をチェックするのは変じゃない?
0830nobodyさん2005/09/30(金) 21:17:53ID:???
それよりロック用ファイル1のロックはどうするんだ
0831nobodyさん2005/09/30(金) 21:28:52ID:???
「破損なし」なのは「ロック用ファイル2」をロックしてるからだけで、
本質的には目新しいアイディアがひとつも無いどころか
単に無駄なことしてるだけに思えるのは気のせいですかそうですか。
0832nobodyさんNGNG
>>828
はなしにならんな。 あきれたよ。もう実家に帰る!
0833nobodyさん2005/12/08(木) 21:09:42ID:pHM0ErCM
perlを始めて3ヶ月位ですが、ファイルロックに
ついて自分なりに色々と試行錯誤した結果、以下の
ようなルーチンを作りました。
flockが使える事が前提ですが、何か欠点や改良点が
あれば指摘して頂けるとありがたいです。

filelock.pl
package filelock;
our %_lock;
sub END {
 foreach my $file ( keys %_lock ) {
  close( $_lock{$file}{'handle'} );
  unlink( $_lock{$file}{'name'} );
  if( $_lock{$file}{'tmp'} ) { rename( $_lock{$file}{'tmp'}, $file ); }
} }
sub readOpen {
 my ( $file ) = @_;
 my ( $handle );
 _append( $file );
 if( !open( $handle, "<$file" )) { return undef; }
 return $handle;
}
0834nobodyさん2005/12/08(木) 21:10:10ID:pHM0ErCM
sub writeOpen {
 my ( $file ) = @_;
 my ( $handle );
 _append( $file );
 if( !$_lock{$file}{'tmp'} ) {
  $_lock{$file}{'tmp'} = $file;
  $_lock{$file}{'tmp'} =~ s/(.*)\.(.*)/$1\.tmp/;
 }
 if( !open( $handle, ">$_lock{$file}{'tmp'}" )) { return undef; }
 return $handle;
}
sub _append {
 my ( $file ) = @_;
 if( $_lock{$file} ) { return; }
 $_lock{$file}{'name'} = $file;
 $_lock{$file}{'name'} =~ s/(.*)\.(.*)/$1\.lck/;
 open( $_lock{$file}{'handle'}, ">$_lock{$file}{'name'}" );
 my $count = 0;
 while( !flock( $_lock{$file}{'handle'}, 2 )) {
  sleep( 1 );
  if( $count++ > 10 ) {
   print '[error]Sarver Busy.';
   exit;
} } }
1;
0835nobodyさん2005/12/08(木) 21:14:40ID:pHM0ErCM
ちなみに、使い方は下記のように使います。

require './filelock.pl';
$file = filelock::readOpen( "count.dat" );
$data = <$file>;
close( $file );
$data = $data + 1;
$file = filelock::writeOpen( "count.dat" );
print $file $data;
close( $file );
0836nobodyさん2005/12/08(木) 23:57:56ID:???
普通にflock使えばいいのにと野暮な突っ込み。

斜め読みしただけだから適当に。
ノンブロッキングロックじゃないと、whileループ内は無駄。
test.txtとtest.datが同じファイルと見なされる。
ロックを解除してるところがない?
サンプルスクリプトはロックが壊れる典型。
0837nobodyさん2005/12/09(金) 00:42:03ID:???
>>836
解答ありがとうございます。

>ノンブロッキングロックじゃないと、whileループ内は無駄。
そうですね。2(LOCK_EX)ではなくて2|4(LOCK_EX|LOCK_NB)
とすればokですね。

>test.txtとtest.datが同じファイルと見なされる。
まぁ、これは仕様という事で…(^^;

>ロックを解除してるところがない?
ENDの中のcloseで解除しているつもりなのですが
closeではロックは自動的解除されないのでしょうか?

>サンプルスクリプトはロックが壊れる典型。
どういう場合にロックが壊れるのでしょうか?
ご掲示頂けるとありがたいです。
0838nobodyさん2005/12/09(金) 03:18:54ID:???
>>837
ENDブロックは、スクリプトの処理の最後で処理されるので、
自動でアンロックさせたいのなら、返すファイルハンドルをオブジェクトにして、
DESTROYブロックを使ってアンロックさせる。
ついでにcloseも再定義。

ロックについては
http://web.archive.org/web/20040216083853/www98.sakura.ne.jp/~jun/perl/flock.html
08398332005/12/09(金) 03:47:51ID:???
>>838
意図的にENDブロックに書いています。オブジェクトを作ってDEST
ROYブロックでアンロックする方法も考えたのですが…

hoge01.pl
read "data01.dat"
read "data02.dat"
-> hoge02.pl
write"data01.dat"
write"data02.dat"
-> hoge03.pl
write"data03.dat"
end

↑こんな感じで読み書きしたい場合、ファイルアクセスする可能
性のある所全てでオブジェクトを保持していないといけないので、
意図的にグローバルに情報を置いて、スクリプトの終わりでEND
ブロック内で一括に処理したのです。

ところで、"closeも再定義"って何ですか?
0840nobodyさん2005/12/09(金) 12:08:16ID:???
closeの再定義と言ったのは、closeのオーバーライドすること。
closeでロックの開放をするのなら、自前のcloseを書いて、
そこで必要な操作を行ってから、CORE::closeを呼び出すという感じで。

と、考えていたのだけど、
どうも考え方が違ってたっぽいか。
08418332005/12/09(金) 15:36:13ID:???
ちょっと、皆さんが勘違いしているっぽいので詳細を書きます。

readOpen
  戻り値 : ファイルハンドル
  機能 : 指定されたファイルの拡張子をlckに変えたファイルを
  flockして指定されたファイルをオープン。flockが10秒以上で
  きない場合は異常終了。

writeOpen
  戻り値 : ファイルハンドル
  機能 : 指定されたファイルの拡張子をlckに変えたファイルを
  flockして指定されたファイルの拡張子をtmpに変えたファイル
  をオープン。flockが10秒以上できない場合は異常終了。

END
  機能 : readOpen,writeOpenでロックされたファイル(*.lck)を
  close。writeOpenで返したのファイル(ハンドル)を元の名前に
  リネーム。(*.tmp→*.元の拡張子)

引き続き、何か欠点や改良点があれば指摘して頂けるとありがたいです。
0842nobodyさん2005/12/09(金) 16:10:37ID:???
>>841
致命的にやばい点:

ENDの中でlockファイルをcloseした時点でflockは外れるので、
その後のunlockとtmpファイルのrenameがロックなしで行われる。

改善した方がいい点:

readしかしない場合でも排他的にロックしてしまうのは嬉しくない。

ENDが実行されるまでロック状態が持続するので、ロックの保持
期間が長くなりそうだしdaemon的プログラムだとどうすんの?

tmpの書き込み中に問題がでて取りやめたいときの手段がない
(やろうと思えば%filelock::_lockいじる手はあるが...)

リトライ回数が尽きたときにいきなりexitするのは汎用性がない。
せめてdieにしとけばevalでトラップする余地があるのだが。

08438332005/12/09(金) 17:26:00ID:???
>unlockとtmpファイルのrenameがロックなしで行われる。
そうですね。renameは一番最初にやるとして、その後にunlink→
closeでしょうか?closeの前にunlinkってできるのでしょうか?

>readしかしない場合でも排他的にロックしてしまうのは嬉しくない。
ここでは省略しましたが、
 unlockFile( $filename )
   機能 : 強制的に指定されたファイルのロックを解除する。
というルーチンがあります。自分は、デフォルトは「最後まで排
他的にロック」。オプションで「指定したファイルのロックを解除」
っていう感じで考えてます。この方が間違いが無いと思うので。

>tmpの書き込み中に問題がでて取りやめたいときの手段
そうですね。これは、abortLockみたいなルーチンを作って最後の
ENDブロックの中でrenameしないようにすれば良いんじゃないで
しょうか?

>リトライ回数が尽きたときにいきなりexitするのは汎用性がない。
if( $count++ > 10 ) { die "flock busy" }
こんな感じで良いですかね?

まだまだ経験が浅いので、先輩諸氏からの助言は為になります。
他にも欠点や改良点があれば指摘して頂けるとありがたいです。
0844nobodyさん2005/12/09(金) 21:41:26ID:???
>>843
「ファイルを変更する(可能性がある)場合に排他ロック、読むだけで済む場合は共有ロック」
というのはひとつのセオリーだけれども、なぜそれがセオリーなのか、そもそもファイルロックとは何なのかを調べるなどして考えてみましょう。

>readしかしない場合でも排他的にロックしてしまうのは嬉しくない。

という >>842 の指摘にはまったく同意で、デメリットはいくらも思いつくけれど残念ながらメリットはひとつも思い浮かびません。
見境なしに排他ロックというのではファイルロックの魅力が半減以下です。

またファイルを利用している、いないに関わらずロックを離さないというのはお行儀が今ひとつ。各プロセスの実行時間が充分に短く、また起動頻度が比較的低ければ問題は出づらいでしょうけれど、少なくとも誰かに勧めることができるやり方じゃないですね。
08458332005/12/09(金) 22:03:55ID:???
色々な意見を参考に作り直してみました。
前作にあったバグ(read→write→readした時に*.tmpファイルから
読まない)も修正しています。

open
  パラメータ:通常のopenと一緒だけど使えるのは'>'と'<'のみ。
  戻り値:ファイルハンドル
  機能:指定されたファイルの拡張子をlckに変えたファイルを
  flockして指定されたファイルをオープン。flockが10秒以上で
  きない場合は異常終了。
close
  パラメータ:openで得られたファイルハンドルとオプション。
  機能 : 指定されたファイルハンドルを閉じます。オプションで
  1を指定するとロックを解除して書き込みがある場合はリネーム
  して反映。2を指定するとロックを解除して書き込みがある場合
  は*.tmpファイルを削除(つまり書き込みをキャンセル)
END
  機能 : *.lckをclose&unlink。*.tmpがある場合は、元のファイ
  ル名にリネーム。

package filelock;
our %_FileList;
our %_HandleList;
sub END {
 foreach my $filename ( keys %_FileList ) {
  if( $_FileList{$filename}{'temp'} ) { rename( $_FileList{$filename}{'temp'}, $filename ) }
  unlink( $_FileList{$filename}{'lock'} );
  close( $_FileList{$filename}{'handle'} );
} }
08468332005/12/09(金) 22:05:50ID:???
sub open {
 my ( $filename ) = @_;
 my ( $handle, $tempfile, $mode );
 if( $filename =~ /^>.*/ ) { $filename =~ s/^>(.*)/$1/; $mode = 2 }
 elsif( $filename =~ /^<.*/ ) { $filename =~ s/^<(.*)/$1/; $mode = 1 }
 else { return undef; }
 if( $mode == 1 && !( -e $filename )) { return undef }
 if( !$_FileList{$filename} ) {
  my $lockname = $filename;
  $lockname =~ s/(.*)\.(.*)/$1\.lck/;
  open( $handle, ">$lockname" );
  my $count = 0;
  while( !flock( $handle, ( 2 | 4 ))) {
   sleep( 1 );
   if( $count++ > 10 ) { die "flock busy" }
  }
  $_FileList{$filename}{'lock'} = $lockname;
  $_FileList{$filename}{'handle'} = $handle;
 }
 $tempfile = $filename;
 if( $mode == 1 ) {
  if( $_FileList{$filename}{'temp'} ) { $tempfile = $_FileList{$filename}{'temp'} }
  if( !open( $handle, "<$tempfile" )) { die "file open error(read)" }
 } elsif( $mode == 2 ) {
  if( $_FileList{$filename}{'temp'} ) { $tempfile = $_FileList{$filename}{'temp'} }
  else {
   $tempfile =~ s/(.*)\.(.*)/$1\.tmp/;
   $_FileList{$filename}{'temp'} = $tempfile;
  }
  if( !open( $handle, ">$tempfile" )) { die "file open error(write)" }
08478332005/12/09(金) 22:07:31ID:???
 }
 $_HandleList{$handle} = $filename;
 return $handle;
}
sub close {
 my ( $handle, $option ) = @_;
 if( $option && ( $option == 1 || $option == 2 )) {
  close( $handle );
  my $filename = $_HandleList{$handle};
  if( $_FileList{$filename}{'temp'} && $option == 1 ) { rename( $_FileList{$filename}{'temp'}, $filename ) }
  elsif( $_FileList{$filename}{'temp'} && $option == 2 ) { unlink( $_FileList{$filename}{'temp'} ) }
  unlink( $_FileList{$filename}{'lock'} );
  close( $_FileList{$filename}{'handle'} );
  delete( $_FileList{$filename} );
  delete( $_HandleList{$handle} );
 } else {
  close( $handle );
  delete( $_HandleList{$handle} );
} }
1;

例:
require './filelock.pl';
$file = filelock::open( "<count.dat" );
$data = <$file>;
filelock::close( $file );
$data = $data + 1;
$file = filelock::open( ">count.dat" );
print $file $data;
filelock::close( $file, 1 );
0848nobodyさん2005/12/11(日) 11:36:06ID:???
わぁ。。 もっとシンプルなやり方あるのにぃ〜
0849nobodyさん2005/12/11(日) 15:20:09ID:???
my ( $filename ) = @_; まで読んだ。
0850nobodyさん2005/12/11(日) 23:38:47ID:???
どうせ>>848は、「じゃあ、そのやり方を書いてみろ」
と言ったところで、その案に穴があるか、書けないか
どっちかだろ?…という訳で、とりあえず

>>848
じ ゃ あ 、 そ の や り 方 を 書 い て み ろ
0851nobodyさん2005/12/12(月) 10:42:51ID:???
unlinkしてからcloseもだめです。

(Aが正常にロックを取得した状態から)
B: open
A: unlink
C: open
A: close
B: flock(成功する)
C: flock(成功する)

flockを使うときはロックファイルは一度作ったら消さないのが
わかりやすい。

どうしても削除したければ、その操作をするためのロックを
別にするとかややこしいことをする羽目になる。
0852nobodyさん2005/12/12(月) 21:10:57ID:???
>>851
ん?Aがロックした状態なんだよね?
B: open -> Aがロック中なので開けない
A: unlink -> 自分がロック中なので削除できる
C: open -> Aがロック中なので開けない
A: close -> 自分のロックを外す
B: flock(成功する) -> Bがロック
C: flock(成功する) -> Bがロック中なので開けない…のでわ?
0853nobodyさん2005/12/12(月) 21:21:39ID:???
>>852
flockによるロック中でもopenはできるのでBはopenできるし、
Aが削除した後はそのファイルは存在しないんだから、
Cは新たに同じ名前の別のファイルを作ってopenできる。
そしてことのきBとCがそれぞれロックファイルだと思って
開いたファイルは実は別のものになるというのが問題
なのです。
0854nobodyさん2005/12/12(月) 22:29:46ID:???
>>853
削除したらロックが外れるのは初耳だ。
つちの環境だと
open -> unlink -> sleep(10) -> close
で、sleep(10)の間はflockできないんだが…。

>flockによるロック中でもopenはできるので
>>833(845)のソースではopenする前にflockの
確認してると思うけど、そりゃ、perlが内部で
flock処理に入ったタイミングで他プロセスが
openしたらできるかもしれないが、そしたら
flock自体意味無しって事になるぞ?
0855nobodyさん2005/12/12(月) 22:33:12ID:???
正:うちの環境
誤:つちの環境

とりあえず>>853は>>833(845)のソースを実際に実行して
穴があってから発言したら?
"俺予想"だけで発言しても意味無いよ。
0856nobodyさん2005/12/12(月) 22:39:11ID:???
>>854
削除したらロックがはずれるのではなくて、同じ名前のロック
ファイルを別に作れてしまう。sleep(10)の間にロックファイルを
openしようとしたら存在しないので新しいファイルが作られてしまう
から、当然flockもできるでしょ。

> openする前にflockの 確認してると思うけど
flockはopenした後のファイルハンドルに対する操作
だから、openしてないのにできるわけないよ。ロックファイルの
openと操作したいファイルのopenを混同してない?
0857nobodyさん2005/12/13(火) 00:46:00ID:???
package filelock;
や
sub open
や
sub close
見ただけで、他のところ見る気なくすね。
0858nobodyさん2005/12/13(火) 01:24:36ID:???
>>856
なるほどね。
しかし、open→flockの間にflockされる問題を回避する事なんてできるの?

>>857
スレタイを百万回読んでスレの趣旨が名前なんて関係無いという事に気付け。
0859nobodyさん2005/12/13(火) 23:21:49ID:???
> しかし、open→flockの間にflockされる問題を回避する事なんてできるの?
げらげら
sub openとか、package filelockなんか平気で使ってる奴はやっぱりレベル低いねえ。
0860nobodyさん2005/12/14(水) 00:31:33ID:???
せっかくのflockが泣いてるぜ。。
0861nobodyさん2005/12/14(水) 05:19:12ID:???
>>859
漏れは>>858だけど>>833じゃないんだけどなぁ。
なんか、このスレは文句ばっかりで意欲的に書き込んでる>>833を
援護しただけなんだけど、文句言うだけがスレの趣旨みたいね。

スレ汚しスマソ。
0862nobodyさん2005/12/14(水) 07:59:40ID:???
> しかし、open→flockの間にflockされる問題を回避する事なんてできるの?
じゃなくて、その問題が起きないようにしないとロックになってないわけよ。
一番簡単なのは851で指摘してる通りロックファイルを削除しないこと。

ただの文句としか言えない書き込みがあるのも確かだが、まじめに
バグを指摘してるのにひとくくりにして文句とか言われてもなぁ。
08638332005/12/14(水) 10:14:13ID:???
>>848-862
色々とご指摘ありがとうございます。ロックファイルをunlinkす
ると、close前にロックファイルがopen(作成)できてしまう問題を
回避する為にunlinkしない事にしました。
しかし、それだと*.lckが沢山できてしまうので、filelockディレ
クトリを作ってその中に作る事にしました。同様に書き込み用の
テンポラリファイルもその中に作るようにしたので、今までの
*.lckや*.tmpファイル名が使えなかったり拡張子だけが違うファ
イルが扱えない問題も無くなりました。
その代わり、各ディレクトリにfilelockという名前のディレクト
リができます。以下にソースを晒します。

sub open {
  my ( $filename ) = @_;
  my ( $handle, $mode );
  if( $filename =~ /^>.*/ ) { $filename =~ s/^>(.*)/$1/; $mode = 2 }
  elsif( $filename =~ /^<.*/ ) { $filename =~ s/^<(.*)/$1/; $mode = 1 }
  else { return undef; }
  if( $mode == 1 && !( -e $filename )) { return undef; }
  $filename =~ /(.*)(\\|\/)(.*)/;
  if(! -d "$1$2filelock") {
    mkdir("$1$2filelock", 0755);
    mkdir("$1$2filelock/tmp", 0755);
  }
  if( !$_FileList{$filename} ) {
    $filename =~ /(.*)(\\|\/)(.*)/;
    my $lockfile = $3 eq '' ? "$1$2filelock/$filename" : "$1$2filelock/$3";
    if( !open( $handle, ">$lockfile" )) { die "file open error" }
    my $count = 0;
    while( !flock( $handle, ( 2 | 4 ))) {
08648332005/12/14(水) 10:14:38ID:???
      sleep( 1 );
      if( $count++ > 10 ) { die "flock busy($lockfile)" }
    }
    $_FileList{$filename}{'lock'} = $lockfile;
    $_FileList{$filename}{'handle'} = $handle;
  }
  if( $mode == 1 ) {
    my $openfile = $filename;
    if( $_FileList{$filename}{'temp'} ) { $openfile = $_FileList{$filename}{'temp'}; }
    if( !open( $handle, "<$openfile" )) { die "file open error" }
    $_HandleList{$handle} = $filename;
    return $handle;
  } elsif( $mode == 2 ) {
    my $openfile = $filename;
    if( $_FileList{$filename}{'temp'} ) { $openfile = $_FileList{$filename}{'temp'};
    } else {
      $filename =~ /(.*)(\\|\/)(.*)/;
      my $tempfile = $3 eq '' ? "$1$2filelock/tmp/$filename" : "$1$2filelock/tmp/$3";
      $_FileList{$filename}{'temp'} = $tempfile;
    }
    if( !open( $handle, ">$openfile" )) { die "file open error" }
    $_HandleList{$handle} = $filename;
    return $handle;
  }
  return undef;
}

引き続き、欠点や改良点があれば指摘して頂けるとありがたいです。
0865nobodyさん2005/12/14(水) 14:36:11ID:???
というか、排他制御の何たるかが理解できてないのに、
いくらコード書いたって無駄だろ。
少なくとも誰も使わんと思うが。
0866nobodyさん2005/12/14(水) 20:09:27ID:???
文句しか書かない厨は、華麗にスルーでおながいすまつ。
0867nobodyさん2005/12/15(木) 00:56:13ID:???
文句にしか聞こえない馬鹿は、似非ロックをバグと一緒に作っていなさい。
0868nobodyさん2005/12/15(木) 06:51:32ID:???
>>867
すげー苦しい言い訳だ。>>865が文句に見えないなら
小学校の国語からやりなおした方が良いよマジで。
とりあえず漏れが>>865が文句だと思う具体的な根拠は…
・どこが問題なのか具体的な事が書かれていない
・自分の中の意見を「誰も」と書くことで皆と同じだと思い込んでる
・文章が全体的に罵倒した口調。何かイヤな事でもあったの?(w

>>833
最初に比べると随分マシになったと思うよ。
具体案を何も提示しないアホな煽りに構わず頑張って欲しい。
0869nobodyさん2005/12/15(木) 07:53:45ID:???
>>865-367
2ちゃんねるですからねー
煽り煽られはあたりまえ
荒らしはスルーが基本ですよ
0870nobodyさん2005/12/15(木) 09:24:29ID:???
なんてルーチン内でロック失敗してundef返すのとdieで処理を完結させるのが
混在してるの?
0871nobodyさん2005/12/15(木) 09:53:36ID:???
もちっとプログラミングができるようになってからやろうな。
まだ君には早いよ。
0872nobodyさん2005/12/15(木) 10:22:47ID:???
みんなに使って欲しい、というんではなく、Perlの勉強として
やってんでしょうから、大目に見てやんなって。
0873nobodyさん2005/12/15(木) 11:10:51ID:???
perlの勉強の前に排他制御の勉強しないから似非ロックが量産される。
0874nobodyさん2005/12/15(木) 12:01:28ID:???
>>870
ファイルが無かったりオプションの指定が違ったりだとundefしてて、
ファイルに書き込めなかったりロックできなかったりするとdieしてる。
たぶん、見た感じだとundefは想定内(?)のエラー。dieは想定外(?)
のエラーって感じじゃないのかな?
0875nobodyさん2005/12/15(木) 12:09:03ID:???
漏れは>>883のソースで十分に排他制御できてると思うんだけど
とりあえず>>865>>873が言う「排他制御」と>>833のソースの
排他制御は何が違うのか具体的に書いてくれまいか?
0876nobodyさん2005/12/15(木) 22:24:03ID:???
>>883
頑張れ。
0877nobodyさん2005/12/16(金) 01:11:58ID:???
>>875
「これだから排他制御を理解してない香具師は…」って
言いたいだけなんだよ。そっとしといれやれ(w
0878nobodyさん2005/12/16(金) 01:57:10ID:???
>>833
排他的なロックに対しては、それで良いと思う。テンポラリファイルを作って書き込み
エラーにも対応してるし。しかし、それで全てOKという訳では無い。
例えばAというファイルをプロセス1〜10が同時に読み込み処理が行われて書き込み処理が
無い場合を考えてみよう。プロセス1が読み込み終わるまでプロセス2は読み込み処理を
行えない。読み込み処理だけならば排他的なロックは必要無いのに。
まぁ、それをわかっていて>>833が何でも排他的なロックを使っているなら良いのだが…
0879nobodyさん2005/12/16(金) 03:04:17ID:???
こうだろ?

× 読み込み処理だけならば排他的なロックは必要無いのに。
○ 読み込み処理だけならば排他的なロックは必要無いケースもあるのに。

0880nobodyさん2005/12/16(金) 05:43:26ID:nqW99XKP
ソースは他のところに上げて、そのURLを書いてください。
すごく邪魔
0881nobodyさん2005/12/16(金) 05:44:47ID:nqW99XKP
なにがなんでも「データを取得できずに空ページを表示」というのを防ぎたいんじゃないのかなぁ?
って思ったり。
0882nobodyさん2005/12/16(金) 12:06:00ID:???
書き込みオープンだけを行うと、一回目と二回目で違うファイルを開かないか。
0883nobodyさん2005/12/17(土) 01:28:51ID:???
>>882
開かないと思うけど…。それに追記に対応してないみたいだから
1回目も2回目も「新規ファイル作成」扱いになるんだよね?
0884nobodyさん2005/12/17(土) 02:42:54ID:???
>>864で、書き込みファイルの指定が
> my $openfile = $filename;
> if( $_FileList{$filename}{'temp'} ) { $openfile = $_FileList{$filename}{'temp'};
てなことになってる。

「書き込みを行って読み込み」を行うとすると、
まず書き込みで$filenameに書き込まれて、
読み込みで$_FileList{$filename}{'temp'}が読まれることになると思われる。
0885nobodyさん2006/01/08(日) 16:25:04ID:???
test
0886nobodyさん2006/01/11(水) 15:20:26ID:???
で、結局どうなったの?
0887nobodyさん2006/01/11(水) 18:09:12ID:???
      ______       ______
     r' ,v^v^v^v^v^il    /          ヽ
     l / jニニコ iニニ!.   /  ジ  き  ぼ   l
    i~^'  fエ:エi  fエエ)Fi  !   ャ  れ  く    l
    ヽr      >   V  !   イ  い  は   l
     l   !ー―‐r  l <.   ア  な       l
 __,.r-‐人   `ー―'  ノ_ ヽ  ン         /
ノ   ! !  ゙ー‐-- ̄--‐'"ハ ~^i \_       _ノ
 ヽ ! ヽ、_     _.ノ  i  \    ̄ ̄ ̄ ̄
ヾV /              ! /.入
0888nobodyさん2006/01/23(月) 18:41:58ID:???
renameでロックをしてみました。どうでしょうか?
  $nowsec=time;
  $lockname="./lock/lock_".$nowsec;
  $basename="./lock/lock";
  while (1){
  if (rename $basename,$lockname){&process()};
  $n++;
  if ($n>=5){&error()};
  sleep 1;
  };
  opendir (LOCKDIR,lock);
  @filelist=readdir(LOCKDIR);
  closedir(LOCKDIR);
  foreach $filename (@filelist) {
  if ($filename=~/_/) {
  ($dest,$locktime)=split(/_/,$filename,2);
    unless ($locktime==$nowsec){
    $timedif=$nowsec-$locktime;
      if ($timedif>=5){
      rename $filename,$lockname;
      };
    };
  };
sub process{
  &backname()
}
sub backname{
  rename $lockname,$filename;
}
0889nobodyさん2006/01/28(土) 10:06:37ID:JFqaWvHV
ファイルロックと言うのは、
先にファイルを開いておいて、それからロックするものですか?

オープン前に排他制御かけるのは無駄ですか?
0890nobodyさん2006/01/28(土) 12:03:17ID:???
有効。
0891nobodyさん2006/01/29(日) 01:06:29ID:???
>>889
flockだとファイルハンドルが必要だから先にオープンしないといけない。
08928892006/01/29(日) 07:30:55ID:rUKuWvJe
@dataにデータがある分だけ、ファイルF1とF2に全く同じデータを上書きしたい場合
こんな感じでいいのでしょうか?
上書きする部分だけループにしています。添削してもらえませんか?

open(F1,">$file1")||die();
flock(F1,LOCK_EX);
open(F2,">$file2")||die();
flock(F2,LOCK_EX);
foreach(@data){
($aaa,$bbb)=split(',',$_,2);
print F1 "$aaa,$bbb\n";
print F2 "$aaa,$bbb\n";
}
close(F1);
close(F2);
■ このスレッドは過去ログ倉庫に格納されています