2010-12-28 27 views
12

¿Hay alguna forma de sincronizar las funciones en PHP para garantizar que dos o más usuarios no puedan ejecutar la misma función al mismo tiempo?Funciones sincronizadas en PHP

+1

Creo que debe proporcionar un poco más de información aquí. ¿La función que intentas ejecutar no es segura? – sberry

+1

Este hilo es un poco antiguo, pero creo que esta es una muy buena respuesta: [Stackoverflow] (http://stackoverflow.com/questions/4710869/php-threads-and-synchronization) – Nicsoft

Respuesta

12

Creo que puede lograr lo mismo (si está disponible) usando sem_acquire para adquirir un semáforo (ingresando a la sección crital) y sem_release para liberar el bloqueo.

+5

sem_acquire y sem_release no están disponibles por defecto y no están disponibles en Windows http://www.php.net/manual/en/intro.sem.php – Lukasz

+0

@Lukas Supongo que es cierto. – Alfred

2

No puedo pensar en ningún problema que pueda enfrentar. Sin embargo, una vez tuve que escribir un script PHP que estaba haciendo algunos cálculos complejos y tuve que asegurarme de que no fue ejecutado simultáneamente por dos usuarios. Para lograr eso, creé un archivo vacío al comienzo del script y lo eliminé cuando los cálculos se completaron. Por supuesto, el script verificó si el archivo existía antes de comenzar los cálculos.

+1

Sin embargo, una base de datos puede ser más rápida. –

+0

Siempre tengo razón, Lucasz. :) –

+0

considere esto: prcess 1 cecks i el archivo existe y no existe. Luego, el proceso termina y la tarea finaliza, y se procesa dos veces, comprueba si existe y porque el segundo no lo ha creado. ¡Ambos procesos se ejecutarán al mismo tiempo!Su solución reduce el riesgo pero no lo elimina. Deberías usar sem_aquire como sugirió Alfred. –

3

Puede usar el bloqueo externo, por ejemplo, bloqueo de archivos a través de flock. Crea un archivo en alguna parte y haz que el script lo bloquee. También puede usar semaphores, pero esos son solo Unix.

1

Tenga en cuenta que el bloqueo de archivos locales y semáforos solo funciona si tiene un servidor web. Si su script está alojado en varios servidores con equilibrio de carga, tendrá que buscar algún otro mecanismo de bloqueo, por ejemplo, un "servidor de bloqueo" especializado en una máquina o algún tipo de bloqueo de archivos sobre NFS.

0

En el pasado, he creado bloqueos simples en registros en la base de datos. Si está procesando un registro existente, puede almacenar su tipo, id y la hora del bloqueo. Asegúrese de que el tipo y el ID sean la clave de la tabla de la base de datos (o de la memoria caché). Cuando comienza el proceso, adquiere el bloqueo de una manera que no borrará un bloqueo existente. Si hay un bloqueo caducado, tómalo. Si hay un bloqueo existente que no ha caducado, no se puede iniciar el proceso (ya sea cola o devolución). Si no había un candado, o si había un candado vencido existente, estás dorado. Ahora tienes el candado. Cuando termine, suelte el candado.

Puede vincular este tipo de sistema a los registros que ya están en su base de datos, crear nuevas tablas para el trabajo en progreso, o incluso utilizar un caché externo.

Saludos, Jacob

0

Algunos detalles más sobre por qué necesita el bloqueo sería agradable. Si tiene problemas con las interacciones de la base de datos de los usuarios, se debe buscar el uso de transacciones en el código de su base de datos para que la base de datos procese atómicamente los cambios complejos.

A modo de ejemplo: Consumo de Symfony con el ORM de Doctrine, por lo que mi código de comprometerse por lo general se ve algo como esto:

$conn = Doctrine_Manager::connection(); 
$conn->beginTransaction(); 
try { 
// .. database code .. 
    $conn->commit(); 
} catch(Doctrine_Exception $ex) { 
    $conn->rollback(); 
    // additional exception handling 
} 

Ahora, esto no evitará que los usuarios clobbering entre sí, si que se encuentren modificando el mismo registro al mismo tiempo; sin embargo, se asegurará de que la base de datos se mantenga coherente, es decir, los cambios del usuario A surtan efecto o los cambios del usuario B entren en vigencia, pero nunca un hudge-podge del usuario A y el usuario B cambia dependiendo del estado de ánimo del DB.