7

私はファイル名の配列を持っており、各プロセスは単一のファイルのみを作成して書き込む必要があります。

これは私が来たものです:

foreach ($filenames as $VMidFile) {
    if (file_exists($VMidFile)) { // A
        continue;
    }

    $fp = fopen($VMidFile, 'c'); // B

    if (!flock($fp, LOCK_EX | LOCK_NB)) { // C
        continue;
    }

    if (!filesize($VMidFile)) { // D
        // write to the file;

        flock($fp, LOCK_UN);
        fclose($fp);
        break;
    }

    flock($fp, LOCK_UN);
    fclose($fp); // E
}

しかし、私が頼っているのは好きではありませんfilesize

別の(より良い)方法でそれを行うための提案はありますか?

UPD:簡単に話し合うためのラベルを追加しました

UPD 2現在のスレッドがファイルを作成したfilesizeかどうかを確認する他の信頼できる方法が見当たらないために使用しています(したがって、ファイルはまだ空です)

UPD 3:ソリューションコンディションレースフリーである必要があります。

4

4 に答える 4

4

少し見苦しい解決策として、ロック ファイルをロックし、そのファイルが存在するかどうかをテストすることが考えられます。

$lock = fopen("/tmp/".$filename."LOCK", "w"); // A

if (!flock($lock, LOCK_EX)) { // B
    continue;
}
if(!file_exists($filename)){ // C
    //File doesn't exist so we know that this thread will create it
    //Do stuff to $filename
    flock($lock, LOCK_UN); // D
    fclose($lock);
}else{
    //File exists. This thread didn't create it (at least in this iteration).
    flock($lock, LOCK_UN);
    fclose($lock);
}

これにより、ファイルへの排他的アクセスが許可され、への呼び出しがfopen($VMidFile, 'c');ファイルを作成するかどうかを決定することもできます。

于 2013-01-24T21:25:13.323 に答える
2

ファイルを作成して干渉されないことを期待するのではなく:

  1. 一時ファイルを作成する
  2. 必要なすべてのファイル操作を実行します
  3. rename場所が存在しない場合は、新しい場所に移動します。

技術的にrenameは、宛先が上書きされるため、同時スレッドが衝突する可能性があります。あなたが持っている場合、それはほとんどありません:

if(!file_exists($lcoation) { rename(...

md5_fileこのブロックの後、ファイルの内容が正しいことを確認するために使用できます。

于 2013-01-24T20:42:05.433 に答える
1

セマフォを使用して排他的アクセスを保護できます(UNIX のみ、sysvsem拡張機能がインストールされている場合)。

$s = sem_get(ftok($filename), 'foo');
sem_acquire($s);

// Do some critical work...

sem_release($s);

それ以外の場合は、 も使用できますflock。特別な拡張機能は必要ありませんが、PHP.net のコメントによると、セマフォを使用するよりも少し遅くなります。

$a = fopen($file, 'w');
flock($a, LOCK_EX);

// Critical stuff, again

flock($a, LOCK_UN);
于 2013-01-24T21:03:30.550 に答える
0

fopen 呼び出しでは、モード 'c' の代わりにモード 'x' を使用してください。結果の $fp を確認してください。偽の場合、ファイルは現在のスレッドによって作成されたものではなく、次のファイル名に進む必要があります。

また、PHP のインストール設定によっては、fopen($VMidFile, 'x') が既に存在するためにファイルを作成できない場合に警告を抑制するために、fopen 呼び出しの前に @ を配置することもできます。

これは群れがなくても機能するはずです。

于 2014-02-06T10:19:08.483 に答える