【问题标题】:PHP non-blocking exclusive lockPHP非阻塞排他锁
【发布时间】:2013-03-13 08:26:43
【问题描述】:

我想使用排他/共享的阻塞和非阻塞锁,就像flock() 中的这些锁一样。如何使用信号量来实现这一点?

【问题讨论】:

    标签: php locking flock


    【解决方案1】:

    这取决于用例。

    如果您只在一台服务器上,请使用锁定文件。

    function doSomething() {
      $file = /temp/path/somthing.lock;
      if (file_exists($file)) {
        return false;
      }
      touch($file);
      // Safely mess with things
      unlink($file);
    }
    

    如果您有多个 Web 服务器,例如在负载均衡器后面,同样的事情可以通过在 mysql 中使用表来完成。

    function doSomething() {
      $query = "SELECT * FROM locks WHERE name='something'");
      $res = mysqli_query($query);
      if (mysql_num_rows($res) > 0) {
        return false;
      }
      $query = "INSERT INTO locks (name) VALUES ('something')";
      mysqli_query($query);
      // Safely mess with things
      $query = "DELETE FROM locks WHERE name='something'");
      mysqli_query($query);
    }
    

    Memcache 是另一个具有多机支持的明显候选对象。

    您不应使用 ACP,因为它仅用于缓存。这意味着您无法控制 ACP 存储何时被删除,它可能随时发生。

    您也可以使用信号量,但是如果您使用多个服务器,则需要注意与锁定文件相同的注意事项。

    我建议创建 lock($key)、is_locked($key) 和 release($key) 函数,然后在整个项目中认真地使用它们。这样您就可以从锁定文件开始(快速实现),然后在不编辑其余代码的情况下升级到更好的东西。如果您想真正花哨,可以将它们实现为记录器对象的方法,并将其放在代码的已知位置。

    【讨论】:

    • Tnx 为例,但我担心它们会受到竞争条件的影响? en.wikipedia.org/wiki/Race_condition
    • 嗯,是的,从某种意义上说是。然而,这并不是因为这些例子,而是 IP 协议的副作用,它不能保证时间。您能做的最好的事情就是阻止多个请求通过。
    • @cmc 什么? IP的网站效应?对于 MySQL,您只需在 locks.name 上有一个唯一索引,并且第一个可以成功创建记录的客户端持有锁。任何进一步的请求都将导致重复键错误。
    • @Shi:这怎么不是竞争条件?你能确定哪个请求将是第一个吗?此外,我更喜欢避免错误而不是捕捉错误,所以我的日志会显示严重的内容。
    • @cmc 这取决于您要强调的方面。当然,两个请求都会争夺锁,但是由于操作是原子的,只有一个可以得到它。所以从某种意义上说“在特殊情况下,两个请求都可以获得锁”,它不是竞争条件。关于您的“错误”-如果您不想进行阻塞锁定,则无法避免错误。请求锁但无法获得锁的实例将发出错误信号。如果使用数据库表,错误称为“重复键”,如果使用某些 Unix 系统调用,则为“EEXIST”。
    猜你喜欢
    • 1970-01-01
    • 2021-07-25
    • 2014-04-04
    • 2011-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多