2008-10-08 13 views
6

Ich bin meistens vertraut mit Java, C und C++, in denen es Möglichkeiten gibt zu kontrollieren, dass nur ein Thread auf eine Ressource zu einem bestimmten Zeitpunkt zugreift. Jetzt bin ich auf der Suche nach etwas ähnlichem, aber in PHP 5.x.PHP 5.x synchronisierter Dateizugriff (keine Datenbank)

Ich habe eine ASCII-Datei, die nur einige speichert, den Wert eines Seitenladezählers:

Zu meinem Problem mit einem Beispiel zu formulieren. Bei der Anwendungsbereitstellung hält die Datei einfach eine 0. Für jeden Zugriff wird der Wert um eins erhöht. Das Ziel ist es, die Seitenladungen zu verfolgen.

Das Problem tritt auf, wenn viele Benutzer gleichzeitig auf die Seite mit dem Zähler zugreifen. Wenn Thread A den aktuellen Wert gelesen hat, also 11, liest ein anderer Thread, den wir B nennen, den Wert immer noch 11. Dann erhöht der erste Thread A den gelesenen Wert und schreibt 12 in die Datei und schließt sie. Dann erhöht der zweite Thread B den gelesenen Wert, der 11 war, erhält 12 und schreibt diesen in die Datei. Der Wert 12 wird in der Datei gespeichert, wenn er eigentlich 13 hätte sein sollen.

In einer anderen Programmiersprache hätte ich dies mit einem Mutex gelöst. Ich verstehe, dass es Mutexe, geteilten Speicher und andere Funktionen als Teil von Modulen gibt. Aber ich hätte gerne eine Lösung, die auf den meisten Servern funktioniert. Plattformunabhängig. Installiert auf den meisten günstigen Web-Hosts. Gibt es eine gute Lösung für dieses Problem? Und wenn nicht, welchen Weg würden Sie nehmen, wenn Sie eine Datenbank verwenden, ist keine Option?

Antwort

7

Sie könnten PHP-Variante der Herde versuchen (http://www.php.net/flock)

ich etwas Ähnliches vorstellen würde (dies setzt voraus, dass die Datei /tmp/counter.txt bereits existiert und hat einen Zähler in der Datei):

<?php 

$fp = fopen("/tmp/counter.txt", "r+"); 

echo "Attempt to lock\n"; 
if (flock($fp, LOCK_EX)) { 
    echo "Locked\n"; 
    // Read current value of the counter and increment 
    $cntr = fread($fp, 80); 
    $cntr = intval($cntr) + 1; 

    // Pause to prove that race condition doesn't exist 
    sleep(5); 

    // Write new value to the file 
    ftruncate($fp, 0); 
    fseek($fp, 0, SEEK_SET); 
    fwrite($fp, $cntr); 
    flock($fp, LOCK_UN); // release the lock 
    fclose($fp); 
} 

?> 
+0

Informative Antwort mit einer Lösung für das Beispielproblem, danke! Ich denke, Calling Flock ($ fp, LOCK_UN) ist nett, obwohl fclose ($ fp) auch die Sperre freigibt. Ich habe jedoch eine Frage, warum hängen Sie die Leerzeichen vor dem Zeilenumbruch in fwrite ($ fp, $ cntr. "\ N") an? –

+0

Hoppla, das war ein Rest meiner ursprünglichen Entwicklung. Ich würde nur fseek ohne den ftruncate verwenden. Das Hinzufügen der Leerzeichen garantiert, dass es alle anderen Zeichen löscht, die in der Zeile waren (wichtiger für das Dekrementieren.) Oben bearbeitet, da es nicht mehr benötigt wird. – terson

3

Die Funktion PHP flock() ist der Weg zu gehen. Sie müssen jedoch sicherstellen, dass alle Zugriffe auf die Datei durch einen Aufruf von Flock() geschützt werden. PHP prüft nicht, ob die Datei gesperrt ist, es sei denn, Sie machen dies explizit.

Das Konzept ist praktisch identisch mit Mutexe (gemeinsame Ressourcen zu schützen, ua), aber es ist wichtig genug, um besondere Betonung zu tragen.