在PHP中锁定以实现政治部分

目标是让PHP脚本中的代码的某个部分一次只能由一个线程/进程执行。

一些限制:

  • 信号量在我的系统上不可用
  • 该手册提到flock()不能在多线程服务器中依赖,所以flock()不在。 (证实了这一点)
  • 所以认为这将是可能的(为什么不?)使用MySQL进行同步,但我得到意想不到的结果。

    为了测试,我使用脚本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);

    该表是:

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

    我转到第一个浏览器选项卡并访问该脚本。 我等待5秒钟,转到另一个选项卡并访问脚本,以便两个脚本并行运行。 我期望第一个选项卡等待,第二个选项卡应在第一个查询后退出。 但是,两个选项卡都在sleep()行上等待。 这意味着第一个查询总是返回'NOT_RUNNING'。

    一些奇怪的事情:

  • 当我重复上述实验时,我在FireFox中运行了两个选项卡,然后在第三种不同的浏览器类型中运行Chrome,然后运行它! (当状态为RUNNING时,睡眠状态,脚本提前退出时状态设置为RUNNING)
  • 当我使用两个不同的命令行窗口重复上述实验并从命令行运行脚本时,它可以工作!
  • 我在等待时检查phpMyAdmin,状态得到正确更新。
  • 我已经尝试了一切,锁定表,事务,SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED,SET autocommit = 1 ;,但总是相同的结果。

    有人知道这里发生了什么吗? 这个问题有什么好的解决方案吗?

    系统测试: - Win,MySQL 5.0,PHP 5.3 - Linux,MySQL 5.0.91-community-log,php 5.2.12

    我完全卡在这里,谢谢你看看!


    更新:

    感谢您提交答案 - 我仍然无法解决此问题。 这里是建议使用GET_LOCK()和session_write_close()的代码:我也尝试了行级锁定,事务和不同的隔离级别。 也许它不能做到?

    
    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();

    第二个浏览器窗口没有挂在sleep命令上。 它阻塞,因为会话阻塞(因此它试图打开同一个会话)。 如果您不再需要它(因此不希望它被阻止),可以使用session_write_close关闭当前会话...


    Mysql有一个名为GET_LOCK的函数。

    链接地址: http://www.djcxy.com/p/69653.html

    上一篇: Locking in PHP to acheive a crtitical section

    下一篇: PHP Parse error: syntax error