Pregunta

El objetivo es tener un script PHP con una cierta sección del código que sólo puede ser ejecutado por un hilo / proceso a la vez.

Algunas restricciones:

  • semáforos no disponibles en mi sistema
  • El manual menciona que flock () no puede ser invocado en los servidores multi-hilo, por lo que flock () está fuera. (Confirmado)

Así que pensó que sería posible (¿por qué no?) El uso de MySQL para la sincronización, pero estoy obteniendo resultados inesperados.

Para la prueba, tengo dos pestañas del navegador abrirá con el guión prueba.php

mysql_connect($dbhost, $dbusername, $dbpassword); mysql_select_db($database_name);

$sql = "SELECT my_val FROM my_table WHERE my_var='status' "; $result = mysql_query($sql)or die(mysql_error()); $row = mysql_fetch_array($result, MYSQL_ASSOC); echo "status is:".$row['my_val']."
\n"; mysql_free_result($result);

if ($row['my_val']=='RUNNING') die ('process is already running!');

// entering critical section

$sql = "UPDATE my_table SET my_val='RUNNING' WHERE my_var='status' "; mysql_query ($sql);

sleep(10); // do some work here. echo 'finished work
';

// leave critical section. let the others know $sql = "UPDATE my_table SET my_val='NOT_RUNNING' WHERE my_var='status' "; mysql_query ($sql);

La tabla es la siguiente:

CREATE TABLE `my_table` (
  `my_var` varchar(255) NOT NULL default '',
  `my_val` varchar(255) NOT NULL default '',
  PRIMARY KEY  (`my_var`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `my_table`
VALUES (
'status', 'NOT_RUNNING'
) 

Voy a la primera pestaña del navegador y acceder a la secuencia de comandos. Espero 5 segundos, ir a la otra pestaña y acceso a la secuencia de comandos de modo que ambas secuencias de comandos se ejecutan en paralelo. Espero que la primera pestaña de esperar, y la pestaña segunda debería salir después de la consulta primero. Sin embargo, ambas pestañas esperan en la línea de suspensión (). Esto significa que la primera consulta siempre devuelve 'NOT_RUNNING'.

Algunas cosas raras:

  • Cuando repito el experimento anterior, corro ambas pestañas en Firefox, y luego en una tercera diferente tipo de navegador, Chrome decir, entonces funciona! (Estado se establece en funcionamiento mientras el dormir, salidas de guión temprano, cuando el estado está en funcionamiento)
  • Cuando repito el experimento anterior utilizando dos ventanas de línea de comandos diferentes, y ejecutar el script desde la línea de comandos, funciona!
  • verifico phpMyAdmin mientras se está a la espera, el estado se actualiza correctamente.

He intentado todo, el bloqueo de la mesa, las transacciones, SET Global Transaction AISLAMIENTO DE NIVEL lectura no confirmada, de confirmación automática SET = 1 ;, pero siempre el mismo resultado.

¿Alguien sabe lo que está pasando aquí? ¿Hay alguna buena solución para este problema?

sistemas probados: - Win, MySQL 5.0, php 5.3 - Linux, MySQL 5.0.91-comunidad-registro, php 5.2.12

estoy totalmente atascado aquí, gracias por echar un vistazo!


ACTUALIZACIÓN:

Gracias por enviar sus respuestas - Todavía no pueden resolver este problema. Aquí está el código con GET_LOCK () y session_write_close () como se sugiere: También he tratado de bloqueo a nivel de fila, las transacciones y los diferentes niveles de aislamiento. Tal vez no se puede hacer?

session_write_close();

mysql_connect($dbhost, $dbusername, $dbpassword);
mysql_select_db($database_name);

$sql = "CREATE TABLE IF NOT EXISTS `my_table`  (
  `my_var` varchar(255) NOT NULL default '',
  `my_val` varchar(255) NOT NULL default '',
  PRIMARY KEY  (`my_var`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
";
mysql_query($sql)or die(mysql_error());

mysql_query ("SELECT get_lock('my_lock', 100)");

$sql = "SELECT my_val FROM `my_table` WHERE `my_var`='status' ";
$result = mysql_unbuffered_query($sql)or die(mysql_error());
$row = mysql_fetch_array($result, MYSQL_ASSOC);
echo "status is:".$row['my_val']."
\n"; mysql_free_result($result); if ($row['my_val']=='RUNNING') die ('process is already running!'); // entering critical section $sql = "UPDATE `my_table` SET `my_val`='RUNNING' WHERE `my_var`='status' "; mysql_query ($sql); sleep(10); // do some work here. echo 'finished work
'; // leave critical section. let the others know //$sql = "UPDATE `my_table` SET `my_val`='NOT_RUNNING' WHERE `my_var`='status' "; $sql = "REPLACE INTO `my_table` (`my_var`,`my_val`) VALUES ('status', 'NOT_RUNNING')"; mysql_query ($sql); $result = mysql_query($sql)or die(mysql_error()); mysql_query ("SELECT release_lock('my_lock')"); die();
¿Fue útil?

Solución

La segunda ventana del navegador no está colgado en el comando sleep. Que está bloqueando porque las sesiones son el bloqueo (y por lo tanto está tratando de abrir la misma sesión). Puede cerrar la sesión actual si no lo necesita más (y por lo tanto no lo quieren a bloquear) con session_write_close ...

Otros consejos

MySQL tiene una función llamada GET_LOCK .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top