Question

Le but est d'avoir un script PHP avec une certaine partie du code qui ne peut être exécuté par un thread / processus à la fois.

Certaines restrictions:

  • sémaphores ne sont pas disponibles sur mon système
  • Le manuel mentionne que flock () ne peut être invoquée dans des serveurs multi-thread, donc troupeau () est sorti. (Confirmé)

Alors pensé qu'il serait possible (pourquoi pas?) D'utiliser MySQL pour la synchronisation, mais je suis d'obtenir des résultats inattendus.

Test, j'ai deux onglets du navigateur ouvrir avec le script test.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);

Le tableau est le suivant:

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'
) 

Je vais au premier onglet du navigateur et accéder au script. J'attends 5 secondes, aller à l'autre onglet et l'accès au script afin que les deux scripts fonctionnent en parallèle. Je pense que le premier onglet à attendre, et le 2ème onglet, sortir après la 1ère requête. Cependant, les deux onglets attendent sur la ligne sleep (). Cela signifie que la première requête retourne toujours de la NOT_RUNNING.

Il y a des choses bizarres:

  • Quand je répète l'expérience ci-dessus, je lance deux onglets dans FireFox, puis dans un 3ème autre type de navigateur, par exemple Chrome, il fonctionne! (Statut est RUNNING alors que le sommeil, les sorties de script tôt lorsque l'état est RUNNING)
  • Quand je répète l'expérience ci-dessus en utilisant deux fenêtres de ligne de commande différents, et exécuter le script à partir de la ligne de commande, cela fonctionne!
  • Je vérifie phpMyAdmin alors qu'il est en attente, l'état est mis à jour correctement.

J'ai tout essayé, le verrouillage de la table, les transactions, TRANSACTION SET GLOBAL ISOLEMENT NIVEAU READ UNCOMMITTED, SET = 1 ;, autocommit mais toujours le même résultat.

Quelqu'un sait-il ce qui se passe ici? Y at-il une bonne solution pour ce problème?

Systèmes testés: - Win, MySQL 5.0, PHP 5.3 - Linux, MySQL 5.0.91-community-log, php 5.2.12

Je suis totalement coincé ici, merci pour jeter un oeil!


Mise à jour:

Merci de soumettre vos réponses - je ne peux toujours pas résoudre ce problème. Voici le code avec GET_LOCK () et session_write_close () comme le suggère: J'ai aussi essayé de verrouillage de niveau ligne, les transactions et les différents niveaux d'isolation. Peut-être qu'il ne peut pas être fait?

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();
Était-ce utile?

La solution

La deuxième fenêtre de navigateur n'est pas accroché sur la commande sleep. Il bloque parce que les sessions sont de blocage (et par conséquent, il essaie d'ouvrir la même session). Vous pouvez fermer la session en cours si vous n'avez plus besoin (et donc ne voulez pas au bloc) avec session_write_close ...

Autres conseils

Mysql a une fonction appelée GET_LOCK .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top