トップページperl
62コメント39KB

CGIの基礎知識

■ このスレッドは過去ログ倉庫に格納されています
0001monaloveNGNG
基本に立ちもどって、CGIに関する技術的な解説を試みるスレッドです。
内容はAS-ISで、無保証です。
0012名無しさんNGNG

             / ̄ ̄⌒V⌒ ̄ ̄ヽ― 、
           / / ̄ ̄\V/ ̄ ̄ヽ-、 \
          /  / ̄ ̄\    ̄ ̄\ \ ヽ
          / /  ,― ' ̄⌒V⌒ ̄ヽ― 、_   ヽ
         |  /               \  |
         |  /                  | |
         | / /// /ノノ∧ヽヽヽヽ\ \ ゝ| |
         ∠/// /Vノノ  ヽヽヽヽヽ\ \ ) /
         _VVノ ノノ ノ   V V V  V  /
        /〆ヽ --―-- \≡≡/--―--  /⌒)
        ヽ6 ヽ   __  | | ____   / 8)    ________
        ∠(ヽヽ\/ ○ l\ /l ○ \/ |/)   /
         (/)ヽ~\___/  | |  \___/~  /(/) <  おいぃーーーッス。
         (\ )ヽ \   /_ヽ   / / (ヾ )  \
         (/)  ヽ  | / ____ \ |  /  (/)   \_______
         (\ )   \| /  \ | /   (\)
         (/)     ヽ ̄ ̄ ̄/     (/)
         (\)   /(|   ̄   |)\    (\)
          ――' ̄   ヽ      /   ̄ ̄ヽ―― 、
                 ヽ    /

0013名無しさんNGNG
複数ファイルを同期(?)させながら更新したい場合、flockは
使えるのですか?

いわゆる lockfile を作らないと無理な気がするんだけど、
何せ厨房なものでようわからんのです…。
0014>12NGNG
惚れた
0015名無しさんNGNG
議論はやがて収束する・・・
0016monaloveNGNG
>13
使えます。

flock()によるファイルロックは、危険領域を実現するために使用します。操
作の対象となるファイルが単一であるか複数であるかには全く関係なく、「適
当な」一つのファイルをロックすればよいのです。

実は、ロックする対象は、読み書きを行うファイルそのものである必要はあり
ません。処理とは無関係なダミーのファイルをロックファイルとしても、相互
排除に関してはなんら不都合は生じません。通常そのようにしないのは、ロッ
クのためだけにダミーのファイルを用意しオープンするのが無駄だからです。

処理対象のファイルが複数ある場合は、そのうちのいずれか一つをロックの対
象と決め、全てのプログラムが危険領域の直前でそのファイルをロックするよ
うにすれば、相互排除が実現できます。異なるファイルをロックするプログラ
ムがあると、「マイクが2本(以上)ある状態」になってしまい、相互排除が不
完全になってしまうので注意してください。

処理対象のファイルが複数あっても、相互排除の原則は変わりません。プログ
ラムの中で、ファイル上とメモリ上とで(少しでも)状態が異なる可能性がある
個所は、全て危険領域に含まれるように、ロックとアンロックの位置を決定し
てください。
0017monaloveNGNG
嘘あるいは電波書いてたらツッコミ入れてください…。
勉強し直します。
001813NGNG
ありがとうございます。つまり、

if( flock( どれかのファイル ) ){
 複数ファイルを操作…
}
else{ エラー }

ってことですか?
0019名無しさんNGNG
evalによる呼び出しだとどうでしょう?
flockサポートしていないOSの場合のために、
eval{flock();};とかよくしますが。
0020japuNGNG
ロックできてないのにロック出来てるふりして動くより、死んでくれたほうが有難いと思うが...
0021名無しさんNGNG
flockでロックしたいファイルがNFS上にあると
flockが成功しても排他制御が上手くいかないという話を
よく耳にしますが、
そういう場合はどうしようもないんでしょうか?
0022japuNGNG
そういうときはflockがうまくいく保証が無いので、symlinkとかmkdirを使ってロックかけるしかないのでは?
002321NGNG
やっぱそれしかないですよねえ。
http://tako.2ch.net/test/read.cgi?bbs=perl&key=961217263
↑の22の言ってることが気になるところです。
0024monaloveNGNG
おはようございます。今朝の私のドジを晒します。自戒の意味を込めて書きま
すが、エラーのハンドリングは常に行うよう心掛けましょう。

flock()の挙動を確認しようとして書いた以下のスクリプトは、エラーを出さ
ずに終了しますが、実際にはファイルをロックしません。

#!/usr/bin/perl
use Fcntl;
open(F, ">foo");
flock(F, LOCK_EX);

use行で':flock'タグが欠けているために、LOCK_EXが定義されず、flock(F,
0); として評価され、flock()がエラーになるからです。しかしこのスクリプ
トではエラーメッセージを出力しないので、その誤りに気付くのは難しい。

誤りに迅速に気付くために、以下のように記述する方がよいです。

#!/usr/bin/perl -w
use Fcntl ':flock';
open(F, ">foo") || die $!;
flock(F, LOCK_EX) || die $!;

perlの-wオプションは、未定義のシンボルの使用に関してwarningを出します。
これにより、つまらないタイプミスに起因するバグはチェックできるようにな
ります。

失敗する可能性のある関数の呼び出しは、戻り値をチェックします。"die $!"
は、失敗の原因に関する有用なメッセージ("Bad file descriptor"等)ととも
に終了します。エラーメッセージの意味については、UNIXならばman errno と
して、オンラインマニュアルを参照してください。
0025monaloveNGNG
>18
同じことですが、もう少し別の書き方をすると

1. オープン(FILE1)
2. ファイルのロック(FILE1, LOCK_EX)
3. 一連の処理 # 危険領域
2. ファイルのアンロック(FILE1)
4. ファイルクローズ(FILE1)

です。(エラーのハンドリングは個々に行ってください)

ファイルのアンロックは省略できます。ファイルをクローズする際に、そのファ
イルのロックが獲得されたままであれば、OSによって自動的にアンロックされ
るからです。

逆に言うと、危険領域の一連の処理の最中に、ロック対象のファイルの読み書
きが終わったからといって、ファイルをクローズしてはいけません。ファイル
がアンロックされ、相互排除がそこで終わってしまうからです。ファイルをク
ローズは、危険領域の処理が終了するまで遅延してください。

ロック対象のファイルをオープンしたままプロセスが終了した場合(異常終了
も含む)も、OSによって自動的にアンロックされます。flock()によるファイル
ロックは、(プロセスが無限ループ等で生きのこったままにならない限り)ロッ
クされたまま、ということがありません。
0026monaloveNGNG
>19
どうでしょう? と聞かれても何が「どう」なのかよくわかりませんが…

flock()は、プラットフォームによっては実装されていません。man perlport
を見ると、Mac OS, VMS, RISC OS, VOS, Windows95で実装されていない、と
あります。

実装されていないプラットフォーム上でflock()を実行すると、致命的なエラー
になりプログラムが異常終了します。eval{} で囲むのは、致命的エラーが発
生した場合でも、スクリプトを異常終了させないための便法です。

flock()が実装されていない場合は、単にエラーを無視するのではなく、
flock()以外の手段で相互排除を行うべきです。そうしなければ、プログラム
は正しく動作しません。正しく動作しないプログラムは、有用ではありません。

このような便法が有用な場合もあります。たとえば、ローカルのWindows9xマ
シンでスクリプトをテストする場合など、flock()は実装されていないが、相
互排除も不要だとわかっている(同時に一つのプロセスしか実行されることが
ない)状況で、スクリプトを実行する場合です。しかし、"eval{flock()}" の
ように記述すると、実際のサーバでの運用時にflock()で発生したエラー(多く
は、プログラミング時の誤り)を捉えることができませんので、バグの温床に
なります。常にeval{}でエラーを無視するのではなく、何らかの方法でテスト
用環境であることを識別し、テスト用環境で実行する場合のみflock()をスキッ
プする、というふうに記述した方が、よいと思います。
0027monaloveNGNG
>21
NFS上のファイルに対してflock()を行ったときの挙動は、NFSクライアントお
よびサーバとなるプラットフォームによって異なるはずですが、私はその詳細
を知りません。japuさんは御存知ないですか?

NFSクライアントとしてのFreeBSD 4.0-RELEASEについて言えば、NFS上のファ
イルに対するファイルロックはサポートされていません。
/usr/src/sys/nfs/nfs_vnops.c のnfs_advlock()関数のコメント部分には、
"Currently unsupported."とはっきり書かれています。ただし興味深いことに、
NFS上のファイルに対して行っても、flock()システムコールそのものはエラー
になりません。ローカルファイルをロックした場合と、同じ挙動になります。
つまり、NFSマウントするマシンが複数あれば、個々のマシンごとのロックに
なる、ということです。ファイルがNFS上にあっても、CGIの動作するWWWサー
バが1台であれば、flock()は期待通りに機能する、ということになります。実
際に確かめてはいません。

CGIの動作するWWWサーバが1台であれば、ローカルファイルシステム上にロッ
ク対象となるダミーファイルを用意する、という方法もとれるでしょう。しか
し、公共のサーバでは、ホームディレクトリ以外の使用は困難かもしれません。

たとえプラットフォームとしてNFS上のファイルロックがサポートされていて
も、ロック機能を提供するシステムプログラム(lockd)のバグによって、特定
の状況でうまくロックできないことも有り得ます。Solarisの最近のバージョ
ンであれば問題ないのではないか、という予感がしますが、調べていないので
なんとも言えません。
0028japuNGNG
NFS は状態が無い (stateless) プロトコルなのでロックという概念が無く rpc.lockd を使用してロックを行うはずですが、多くの実装 (商用OS含む) でこの動作はあまり信頼性が無いものと聞いています。
勉強不足の為詳しくは分かりません。

man rpc.lockd ではこうなっています (4.0 RELEASE):
BUGS
The current implementation provides only the server side of the protocol
(ie. clients running other OS types can establish locks on a FreeBSD
fileserver, but there is currently no means for a FreeBSD client to es-
tablish locks).

すくなくともクライアントが FreeBSD の場合はうまく動作しないようです。(あと、FreeBSD の場合は、常に "ロック成功" を返すという話も聞いています。数年前の話で今は直っているのかもしれませんが。)

ただ、NFS越しのファイルに関してflockが常に成功するわけではないというのは昔から良く言われていますのであのように書きました。

----
私も24のようなドジをよくやってしまいます。一度痛い目にあったことがあるので、テストプログラムでも常に -w を付けるようにしています。(もちろん、open MOE, "sakura" or die; のようにチェックも行う。)

# 2ch にしてはまともなスレッドになっているなぁ。
0029japuNGNG
というわけでちょっとテストしてみました。

#! /usr/local/bin/perl -w

use Fcntl ":flock";

open F, "+< test.dat" or die;
flock F, LOCK_EX or die;
$SIG{TERM} = $SIG{KILL} = $SIG{HUP} = $SIG{USR1} = "IGNORE";
$count = <F>;
$count++;
seek F, 0, 0;
truncate F, 0;
print F $count;
sleep 1;
close F;
$SIG{TERM} = $SIG{KILL} = $SIG{HUP} = $SIG{USR1} = "DEFAULT";

__END__

test.dat は他のクライアントからのアクセスがないようにして perl flocktest.pl & ... & perl flocktest.pl & として一気に40個起動して実験してみたところ、

Server / Client
FreeBSD 3.1-RELEASE / FreeBSD 3.1-RELEASE i386 - OK
SGI CHALLENGE L / FreeBSD 4.0-RELEASE i386 - OK
SGI CHALLENGE L / OSF1 V4.0 alpha - OK
SGI CHALLENGE L / IRIX 6.5 IP32 - OK

ちょっとサンプル数が少ないので何とも言えませんが。
0030monaloveNGNG
このスクリプトで、signal無視するのって意味はあるんですか?
0031japuNGNG
この場合は無いでしょうね...
0032名無しさんNGNG
monaloveはカリスマカーネル設計者ですね。
0033monaloveNGNG
排他ロックは、同時に一つのプロセスしか獲得できないロックです。通常、ファ
イルロックと呼ばれるのは、排他ロックです。これに対して共有ロックは、複
数のプロセスが同時に獲得できるロックです。共有ロックは、排他ロックと共
に使用します。

二つのロックの組み合わせには、次のような性質があります。あるプロセスが
排他ロックを獲得すると、他のプロセスは排他ロックも共有ロックも共有ロッ
クも獲得できなくなります。これに対し、あるプロセスが共有ロックを獲得す
ると、他のプロセスは、共有ロックは獲得できますが、排他ロックは獲得でき
なくなります。

ロックをカラオケボックスのマイクに喩えれば、共有ロックは合唱用のマイク、
排他ロックはソロ用のマイクに相当します。合唱用のマイクは複数人で同時に
使用できますが、合唱中はソロ用のマイクを使用することができません。ソロ
用のマイクは、誰もマイクを使用していないときのみ使用でき、ソロが終わる
までは、他の人間は合唱もソロもできません。
0034monaloveNGNG
共有ロックは読込ロック、排他ロックは書込ロックと呼ばれることがあります。
これは次のような、一般的な使い方を示しています。

ファイル上にある情報があります。プロセスがファイルの情報を更新するとき、
他のプロセスは情報を更新したり、読み取ったりしてはいけません。(不完全な情報が読み取られたり、書き込まれたりという問題が発生するからです)
これを保証するために、情報の読み込みあるいは書き込みを行うときに、排他
ロック(だけ)を使用して他のプロセスを排他する、というのが簡単な方法です。
このようにすれば、読み込みあるいは書き込みを行うプロセスは、同時に一つ
しか存在しないことが保証できるからです。

しかしよく考えてみると、書き込みを行うプロセスが同時に複数存在するのは
問題ですが、読み込みを行うプロセスは、同時に複数存在しても問題ないはず
です。読み込みを行うプロセスは、書き込みを行うプロセスだけを排他すれば
よく、他の読み込みを行うプロセスを排他する必要はありません。つまり、排
他ロックだけを使用して相互排除を行う場合、排他する必要のないプロセスま
で排他してしまうことになります。

書き込みを行うプロセスは排他ロックを獲得するが、読み込みを行うプロセス
は共有ロックを獲得するようにすると、この問題を改善できます。あるプロセ
スが読み込みを行っている最中は、他のプロセスが書き込みを行うのは防ぎま
すが、他のプロセスが読み込みを行うのは邪魔しません。あるプロセスが書き
込みを行っている最中は、他の読み書きを行うプロセスの実行は全て防がれま
す。

このように、ロックの一部を共有ロックに変更することで、読み込みを行うプ
ロセスが複数同時に実行できるようになり、システム全体のパフォーマンスが
向上する可能性があります。
0035monaloveNGNG
見出し入れ忘れました…。
33,34は「共有ロックと排他ロックについて」
0036名無しさんNGNG
勉強になるなぁ、age。
0037locker roomNGNG
>monalove

読み込みにロックかけるメリットは?
読み込みが、その他の条件に対して全く事後の影響を
与えない(つまり、記録更新のための読み出しではない)
場合には、必要無いんじゃないかな?
0038locker roomNGNG
あ、わかった、上の質問失敗ね。読み出した情報を
何か他に利用する場合ありってことね。人間が
見るとか以外に。
上の質問無視してくれ。
0039NGNG
>>25
close前のアンロックは、バッファをフラッシュ(ファイルの書き出し)
せずにアンロックしてしまうと言うのを読んだことあるのですが…
0040名無しさん@9月病NGNG
>>39
Perlメモかなにかに書いてあったね。close で自動的に解除してくれるらしい。
flock 使う時はアンロックしてないけどそもそも symlink のしか使わなくなった。
0041名無しさんNGNG
symlink とかで独自実装すると 異常終了時に困りませんか?
SIGKILLじゃなくても 通常のSIGNALであっても。
0042名無しさん@9月病NGNG
数回ロックにトライして駄目なら異常とみなしてロックファイル消して終わらせてます。
少なくともflockでロックかけた上にファイル2重化していたときよりはよっぽどマシです。
今は希にタイムアウトになることはあってもシングルファイルでもファイル飛んでませんし。
0043名無しさんNGNG
ふむふむ
長時間ロックすることが無いならそれでOKですね。
長時間ロックする場合は設計が悪いってことで大丈夫だな。
アイデアいただき。ありがとです。
0044monaloveNGNG
>>39
ごめんなさい。バッファリングのことを忘れていました。
ちゃんとフラッシュしてからアンロックしてください。
(最近のバージョンのperlでは、アンロック時に暗黙にフラッシュして
くれるようですが)
0045なんかNGNG
役に立ちそうなのであげ
0046名無しさんNGNG
役に立ちそうなのであげ


0047マイケル市井NGNG
選挙に勝てそうなのであげ
0048名無しさんNGNG
よし!
0049名無しさんNGNG
白痴氏ねや、ヴォケ
0050名無しさんNGNG
>>49
どうしてそういうこと言うの?悲しいよ・・・
0051名無しさんNGNG
>>50

分かった、「氏ね」じゃなく死ね!いや寧ろ消えろ!!

この世から塵一つ残さず、お前が居た痕跡、記憶さえも残さず
完全に消え去れ!!!
0052名無しさんNGNG
おもむろに糞スレageてんじゃねーよ、ヴォケ。1000回氏ね
0053名無しさんNGNG
私はどうすればいいの?
死ぬのは嫌だ。消えるも嫌・・・
0054名無しさんNGNG
>>53
おまえに決定権は無いんだからさっさと死ね。
0055名無しさんNGNG
見苦しいからやめれ。

--------------終了--------------
0056名無しさんNGNG
>>55
おまえのレスも相当見苦しい。

=== 昇天 ===
0057名無しさん@お腹いっぱい。NGNG
age
0058名無しさん@お腹いっぱい。NGNG
>>57 鯖も変わって板名もレンタルサーバになったんだから
いい加減板違いスレageるの止めれ、ボケ。

過去スレtakoに置いてけぼりで良かった気がする。

#「置いて『け』ぼり」?「置いて『き』ぼり」?
#googleの検索結果じゃどっこいどっこいだ。
0059名無しさん@お腹いっぱい。NGNG
>>58=真性白痴
0060名無しさん@お腹いっぱい。NGNG
>>59=あほ。
0061名無しさん@お腹いっぱい。NGNG
>>61=バカ
0062真・スレッドストッパーNGNG
書けませんよ( ̄ー ̄)ニヤリッ
■ このスレッドは過去ログ倉庫に格納されています