̃Gg[͂ĂȃubN}[Nɒlj

PHP :: flock のバッドノウハウ



以下のような、flock の戻り値を受ける変数名を使いまわすコードは危険。

/**
 * flock バッドノウハウ
 */
 
$fp = fopen('lock', 'w');
flock($fp, LOCK_EX);
 
 :
 :
 
// ↓これが呼ばれた瞬間、上部の`排他ロック'は解除されてしまう。。
$fp = fopen('hoge.txt', 'w');
 
 :
 :


検証のメモ

/**
 * lock.php
 * [usage] % php lock.php arg1 arg2
 * [description]
 * 第一引数に与えられた変数名で fopen(書き込みモード) の戻り値を受け、
 * ロックファイル「.lock1」に対して排他ロックを試みる。
 * 5秒後、第二引数に与えられた変数名の変数に 123 を代入する。
 * さらに5秒後、スクリプトが終了する。
 */
<?php
$$argv[1] = fopen(".lock1", "w");
if (flock($$argv[1], LOCK_EX)) {
    echo '$' . $argv[1] . ": .lock1 success\n";
} else {
    echo '$' . $argv[1] . ": .lock1 failure\n";
}
sleep(5);
 
$$argv[2] = 123;
echo '$' . $argv[2] . " = 123\n";
sleep(5);
 
echo "exit.\n";
?>
/**
 * check.php
 * [usage] % php check.php
 * [description]
 * ロックファイル「.lock1」に対して、1秒おきにノンブロッキングモードで排他ロックを試みて、
 * 結果を出力する
 */
<?php
while (true) {
    $fp = fopen(".lock1", "w");
    if ( ! flock($fp, LOCK_EX | LOCK_NB)) {
        echo ".lock1 failure\n";
    } else {
        echo ".lock1 success\n";
    }
    sleep(1);
}
?>

lock.php, check.php を走らせて検証する

[testcase1] 変数名を違う名前にする

---------------------------------------------------------
% php lock.php fp1 fp2
$fp1: .lock1 success
$fp1 = 123
exit.
------------------------------------------- screen split -
% php check.php
.lock1 failure
.lock1 failure
.lock1 failure
.lock1 failure
.lock1 failure
.lock1 failure
.lock1 failure
.lock1 failure
.lock1 failure
.lock1 failure
.lock1 success ← lock.phpが終了したと同時に排他ロック成功
--------------------------------------------------------- 

[testcase2] 変数名を同じ名前にする

---------------------------------------------------------
% php lock.php fp1 fp1
$fp1: .lock1 success
$fp1 = 123
exit.
------------------------------------------- screen split -
% php check.php
.lock1 failure
.lock1 failure
.lock1 failure
.lock1 failure
.lock1 failure
.lock1 success ← 変数「fp1」が上書きされたと同時に排他ロック成功
.lock1 success
.lock1 success
.lock1 success
.lock1 success
.lock1 success
--------------------------------------------------------- 


結論

fopen を受ける変数を上書きした場合、ファイルポインタがクローズしたとみなされ、flock による排他ロックも解除されると推測される。




programming/php/etc/bad_knowhow_flock.txt