Locking in PHP to acheive a crtitical section
The goal is to have a PHP script with a certain section of the code that can only be executed by one thread/process at a time.
Some restrictions:
So thought it would be possible (why not?) to use MySQL for synchronization, but I'm getting unexpected results.
To test, I have two browser tabs open with the script test.php
mysql_connect($dbhost, $dbusername, $dbpassword); mysql_select_db($database_name);
$sql = "SELECT my_val FROM
my_table
WHEREmy_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
SETmy_val
='RUNNING' WHEREmy_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
SETmy_val
='NOT_RUNNING' WHEREmy_var
='status' "; mysql_query ($sql);
The table is:
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' )
I go to the first browser tab and access the script. I wait 5 seconds, go to the other tab and access the script so that both scripts run in parallel. I expect the first tab to wait, and the 2nd tab should exit after the 1st query. However, both tabs wait on the sleep() line. This means that the first query always returns 'NOT_RUNNING' .
Some odd things:
I have tried everything, locking the table, transactions, SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED, SET autocommit=1;, yet always the same result.
Does anyone know what is happening here? Is there any good solution for this problem?
Systems tested: - Win, MySQL 5.0, php 5.3 - Linux, MySQL 5.0.91-community-log, php 5.2.12
I'm totally stuck here, thanks for taking a look!
UPDATE:
Thanks for submitting your answers - I still cannot solve this problem. Here is the code with GET_LOCK() and session_write_close() as suggested: I have also tried row level locking, transactions and different isolation levels. Perhaps it cannot be done?
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();
The second browser window is not hanging on the sleep
command. It's blocking because sessions are blocking (and hence it's trying to open the same session). You can close the current session if you don't need it anymore (and hence don't want it to block) with session_write_close
...
Mysql有一个名为GET_LOCK的函数。
链接地址: http://www.djcxy.com/p/69654.html上一篇: 这些功能有什么问题?
下一篇: 在PHP中锁定以实现政治部分