Domanda

L'obiettivo è quello di avere uno script PHP con una certa sezione del codice che può essere eseguito da un solo filo / processo alla volta.

Alcune restrizioni:

  • semafori non sono disponibili sul sistema
  • Il manuale menziona che flock () non può essere invocato nei server multi-threaded, quindi flock () è fuori. (Confermato)

quindi ho pensato che sarebbe stato possibile (perché no?) Per utilizzare MySQL per la sincronizzazione, ma sto ottenendo risultati inaspettati.

Per prova, ho due schede del browser aperte con lo 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);

La tabella è:

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

vado alla linguetta primo browser e accedere allo script. Aspetto 5 secondi, andare all'altro scheda e l'accesso lo script in modo che entrambi gli script eseguito in parallelo. Mi aspetto che la prima scheda di aspettare, e il 2 ° scheda dovrebbe uscire dopo il 1 ° query. Tuttavia, entrambe le linguette attesa sulla linea di sleep (). Ciò significa che la prima query sempre restituisce 'NOT_RUNNING'.

Alcune cose strane:

  • Quando ripeto l'esperimento di cui sopra, ho eseguito entrambe le schede in Firefox, e poi in un terzo tipo di browser diverso, diciamo Chrome, allora funziona! (Stato è impostato in esecuzione mentre il sonno, le uscite di script presto, quando lo stato è in funzione)
  • Quando ho ripetere l'esperimento sopra utilizzando due diverse finestre della riga di comando, ed eseguire lo script dalla riga di comando, funziona!
  • I check phpMyAdmin mentre è in attesa, lo stato viene aggiornato correttamente.

Ho provato di tutto, il blocco del tavolo, le transazioni, SET GLOBAL TRANSACTION ISOLATION LEVEL LEGGI UNCOMMITTED, SET autocommit = 1 ;, ma sempre lo stesso risultato.

Qualcuno sa che cosa sta succedendo qui? C'è qualche buona soluzione per questo problema?

sistemi testati: - Win, MySQL 5.0, PHP 5.3 - Linux, MySQL 5.0.91-community-log, php 5.2.12

Sono totalmente bloccato qui, grazie per dare un'occhiata!


UPDATE:

Grazie per la presentazione delle vostre risposte - io ancora non possono risolvere questo problema. Ecco il codice con GET_LOCK () e session_write_close () come suggerito: Inoltre ho provato blocco a livello di riga, transazioni e diversi livelli di isolamento. Forse non si può fare?

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();
È stato utile?

Soluzione

La seconda finestra del browser non è appeso sul comando sleep. Si sta bloccando perché le sessioni stanno bloccando (e quindi sta cercando di aprire la stessa sessione). È possibile chiudere la sessione corrente se non si serve più (e quindi non ne vogliono sapere di blocco) con session_write_close ...

Altri suggerimenti

Mysql ha una funzione chiamata GET_LOCK .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top