2008-10-08 6 views
6

Estoy casi familiarizado con Java, C y C++ en el que hay formas de controlar que solo un hilo está accediendo a un recurso en un momento dado. Ahora estoy en busca de algo similar, pero en PHP 5.x.Acceso de archivo sincronizado PHP 5.x (sin base de datos)

Formular mi problema con un ejemplo:

Tengo un archivo ASCII que sólo almacena un número, el valor de un contador de carga de la página. En la implementación de la aplicación, el archivo simplemente mantendrá un 0. Para cada acceso, el valor se incrementará en uno. El objetivo es realizar un seguimiento de las cargas de página.

El problema surge cuando muchos usuarios acceden concurrentemente a la página que contiene el contador. Cuando el hilo A ha leído el valor actual, digamos que es 11, otro hilo que llamamos B lee el valor, sigue siendo 11. Entonces, el primer hilo A incrementa el valor leído y escribe 12 en el archivo y lo cierra. Luego, el segundo subproceso B, incrementa el valor de lectura, que era 11, obtiene 12 y lo escribe en el archivo. El valor 12 se almacena en el archivo, cuando debería haber sido 13.

En otro lenguaje de programación lo habría resuelto usando un mutex. Entiendo que hay mutexes, memoria compartida y otra funcionalidad como parte de los módulos. Pero me gustaría una solución que funciona en "la mayoría de los servidores" que hay. Plataforma independiente. Instalado en la mayoría de los servidores web baratos. ¿Hay una buena solución a este problema? Y si no existe, ¿de qué manera tomaría si usa una base de datos no es una opción?

Respuesta

7

Usted podría intentar variante de php del rebaño (http://www.php.net/flock)

Me gustaría imaginar algo similar a (esto supone que el archivo /tmp/counter.txt ya existe y tiene un contador en el archivo):

<?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

Respuesta informativa con una solución al problema de ejemplo, ¡gracias! Creo que llamar a flock ($ fp, LOCK_UN) es bueno aunque fclose ($ fp) también libera el bloqueo. Sin embargo, tengo una pregunta: ¿por qué anexa los espacios antes de la nueva línea en fwrite ($ fp, $ cntr. "\ N")? –

+0

Vaya, eso fue un sobrante de mi desarrollo original. Iba a usar fseek sin el ftruncado. Al agregar los espacios, se garantiza que borrará cualquier otro carácter que estuviese en la línea (más importante para disminuir). Editado arriba, ya que ya no es necesario. – terson

3

La función de flock() de PHP es la ruta a seguir. Sin embargo, debe asegurarse de que todos los accesos al archivo estén protegidos por una llamada a flock() primero. PHP no verificará si el archivo está bloqueado a menos que realice la llamada explícitamente para hacerlo.

El concepto es prácticamente idéntico a los mutexes (protección de recursos compartidos, et al), pero es lo suficientemente importante como para tener un énfasis especial.

Cuestiones relacionadas