Foros del Web » Programando para Internet » PHP »

Problema de Concunrencia

Estas en el tema de Problema de Concunrencia en el foro de PHP en Foros del Web. Hola a todos, a ver si es posible que alguien me pueda ayudar, me he vuelto loca buscando todo el dia sobre el mismo asunto ...
  #1 (permalink)  
Antiguo 17/07/2008, 12:11
 
Fecha de Ingreso: junio-2008
Mensajes: 16
Antigüedad: 15 años, 10 meses
Puntos: 0
Problema de Concunrencia

Hola a todos, a ver si es posible que alguien me pueda ayudar, me he vuelto loca buscando todo el dia sobre el mismo asunto y nada para funcionar..

La cuestión es la siguiente:

Tengo una aplicacion web que entre otras cosas realiza la inscripcion de usuarios en talleres. Los talleres tienen unas plazas limitadas, y necesito controlar que no se sobrepasen esas plazas. Cada vez que se intenta inscribir un usuario, compruebo si el numero de plazas es mayor numero de solicitudes de inscripcion y si hay plazas permito la inscripcion. El problema viene cuando solamente queda una plaza libre. En el mejor de los casos, el primer usuario que llegue la ocupará..
pero si dos usuarios justo en el mismo instante ven que queda una sola plaza, se inscribiran los dos.. Entonces habrá mas inscripciones que plazas y esto es un error.

El mismo problema tengo con la ocupacion de una aula en una determinada fecha.

Intentando buscar soluciones pensé en semaforos, pero como corro php bajo xamp en windows no es posible usar semaforos (lei que solo era posible en unix).
¿Esto en lo correcto?

Encontré también un metodo para bloquear un archivo y despues desbloquearlo
Código PHP:
$bloqueo './bloqueo';  // Nombre del archivo de bloqueo

if (is_file ($bloqueo)) {
    print 
"Lo siento, alguien ha bloqueado el sistema.\n" .
     
"Intente mas tarde.\n</pre>\n";
    exit (
1);
}
        
touch ($bloqueo);  // Crear el archivo, creando en efecto un bloqueo
        
// Aqui se hacen todos los procesos criticos... Cosas interesantes que
// contribuyan con la dominacion del mundo, si se quiere.
        
$Resultado=$Taller->InscribirEnTaller();
        
//sleep (5);  // Por ahora, solo retengamos es bloqueo por 5 segundos
        
unlink ($bloqueo);  // Retirar el bloqueo 
Pero este metodo no bloquea a los demas usuarios, a la espera de continuar, siemplemente les informa y sale, si hiciera un while(isset....) sleep(5) quizá pecara de espera ocupada..
Y otro problema que se suma, es que si los demas usuarios quieren inscribirse en un taller del que tambien queda una plaza, aunque sean distintos talleres tambien les afecta. ¿Como bloquear solamente en ese taller y no en todos?

-Otra opcion que encontre era utilizar el patron Singleton.. pero probé y tampoco, se creaban instancias de Singleton desde cualquier clase :S

Alguien me puede ayudar?
Gracias por adelantado.

Última edición por Vera828; 17/07/2008 a las 12:34
  #2 (permalink)  
Antiguo 19/07/2008, 15:08
AlvaroG
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: Problema de Concunrencia

Hola Vera828,

Voy a asumir que estás usando bases de datos, que es la forma más simple de solucionar tu problema.

Antes que nada, siempre deberías comprobar que queden lugares.
Me imagino que tu situación es así

- queda 1 lugar.
- usuario 1 y usuario 2 entran a ver los detalles del taller, a ambos se les muestra que queda 1 lugar.

Lo que deberías hacer es indicar que los datos mostrados pueden no ser los actuales, el usuario debería saber eso de antemano.
Luego, creo que la solución es bastante simple: en el momento en el que el usuario intenta subscribirse, comprobás de nuevo si hay lugares.
Si hay cupos, seguís con la inscripción, si no hay, le mostrás al usuario que no hay lugar.

Dada la velocidad a la que se ejecutan estos procesos, la comprobación y la inserción serán casi instantáneas. Una petición posterior entrará a la comprobación de nuevo, y verá el resultado terminado.

Si aún te preocupa que puedan coincidir (una preocupación completamente válida) lo que deberías hacer es usar transacciones en tu base de datos.
Es decir, hacer que la comprobación y la inserción sean 1 sola consulta.

Me imagino algo como
BEGIN
comprobar()
SI QUEDAN CUPOS
inscribir()

COMMIT

Lo bueno de hacer esto es que ambas consultas se ejecutarán como 1 sola, bloqueando el acceso a la fila: una segunda comprobación inmediatamente luego de la primera, pero antes de la inserción, tendrá que esperar a que la inserción termine.

Me permito recomendarte algo muy básico que escribí sobre el tema: Transacciones en MySQL


Otro problema diferente se daría si en vez de usar bases de datos estás usando archivos de texto, en ese caso deberías hacer algo similar a lo que estás haciendo, creo que una buena forma sería:

crear el archivo de bloqueo
consultar si quedan cupos
si quedan inscribir
borrar el archivo de bloqueo.

Si una consulta entra y el archivo de bloqueo existe, lo que podrías hacer es obtener el número de cupos disponibles, pero no hacer nada, y simplemente mostrar un texto tipo "Otra inscripción está en curso, nos quedan X lugares. Intenta nuevamente en unos segundos"

Espero haberme explicado bien.


Saludos.
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 20:57.