PHP互斥(互斥)

时间:2010-05-27 13:23:32

标签: php mutex mutual-exclusion

阅读有关在PHP中锁定的一些文章 它们主要都指向http://php.net/manual/en/function.flock.php

此页面讨论了如何在硬盘上打开文件!!

真的是这样吗?我的意思是,这使得锁定非常昂贵 - 这意味着每次我想要锁定我都必须访问硬盘)=

能否以令人愉快的消息安慰我?

修改

由于我有一些回复,我想问这个;
我的脚本只能运行一个或几个线程?因为如果它是一个然后我显然不需要互斥量。有简明的答案吗?

我到底想要做什么

ircmaxell提问 这就是故事:

我有两台ftp服务器。我希望能够在我的网站上显示有多少在线用户在线 所以,我认为这些ftp服务器会将他们的统计信息“POST”到某个PHP脚本页面。我们假设此网页的网址为“http://mydomain.com/update.php”。

在网站的主页(“http://mydomain.com/index.php”)上,我将显示累计统计信息(在线用户)。

就是这样。

我的问题是,我不确定当一个ftp服务器更新他的统计数据而另一个同时执行此操作时,信息会变得混杂。 就像多线程时一样;两个线程同时增加一些“int”变量。除非您在它们之间进行同步,否则它不会按预期发生 那么,我有问题吗?是的,不,也许?

可能的解决方案

整天都在努力思考,我在这里有一个想法,我希望你发表意见 如上所述,这些ftp服务器将每隔60秒发布一次他们的统计数据 我正在考虑将此文件设为“stats.php” 它将包含在ftp服务器所在的更新脚本(“update.php”)和“index.php”页面中,访问者可以看到有多少用户在线。
现在,当ftp服务器更新时,“update.php”中的脚本将使用新的累积统计信息修改“stats.php”。
首先,它将读取“stats.php”中包含的统计数据,然后累积,然后重写该文件。

如果我没弄错,PHP会检测到文件(“stats.php”)已更改并加载新文件。正确的吗?

5 个答案:

答案 0 :(得分:31)

好吧,大多数PHP在不同的进程空间中运行(线程实现很少)。容易的就是羊群。它保证可以在所有平台上运行。

但是,如果您在支持中编译,则可以使用其他一些内容,例如Semaphore扩展。 (使用--enable-sysvsem编译PHP)。然后,你可以做类似的事情(注意,sem_acquire()应该阻止。但如果由于某种原因它不能,它将返回false):

$sem = sem_get(1234, 1);
if (sem_acquire($sem)) {
    //successful lock, go ahead
    sem_release($sem);
} else {
    //Something went wrong...
}

你拥有的其他选项是MySQL user level locks GET_LOCK('name', 'timeout'),或使用像APC或XCache这样的东西创建你自己的选项(注意,这不是真正的锁,因为竞争条件可能是创建了其他人在你的检查和接受锁之间锁定的地方。)

编辑:回答您编辑的问题:

这完全取决于您的服务器配置。 PHP可以运行多线程(每个请求由不同的线程提供),也可以运行多进程(每个请求由不同的进程提供)。这一切都取决于您的服务器配置...

非常罕见,PHP将按顺序提供所有请求,只有一个进程(和一个线程)为所有请求提供服务。如果你正在使用CGI,那么它默认是多进程的。如果您使用的是FastCGI,则可能是多进程和多线程。如果您将mod_php与Apache一起使用,那么它取决于工作者类型:

  1. mpm_worker将是多进程和多线程,具有ServerLimit变量规定的进程数。
  2. prefork将是多进程的
  3. perchild也将是多进程的
  4. 修改:要回答您的第二个修改过的问题:

    这很容易。将其存储在一个文件中:

    function readStatus() {
        $f = fopen('/path/to/myfile', 'r');
        if (!$f) return false;
        if (flock($f, LOCK_SH)) {
            $ret = fread($f, 8192);
            flock($f, LOCK_UN);
            fclose($f);
            return $ret;
        }
        fclose($f);
        return false;
    }
    
    function updateStatus($new) {
        $f = fopen('/path/to/myfile', 'w');
        if (!$f) return false;
        if (flock($f, LOCK_EX)) {
            ftruncate($f, 0);
            fwrite($f, $new);
            flock($f, LOCK_UN);
            fclose($f);
            return true;
        }
        fclose($f);
        return false;
    }
    
    function incrementStatus() {
        $f = fopen('/path/to/myfile', 'rw');
        if (!$f) return false;
        if (flock($f, LOCK_EX)) {
            $current = fread($f, 8192);
            $current++;
            ftruncate($f, 0);
            fwrite($f, $current);
            flock($f, LOCK_UN);
            fclose($f);
            return true;
        }
        fclose($f);
        return false;
    }
    

答案 1 :(得分:1)

问题是:在哪里将FTP服务器推送的统计信息存储到您的update.php文件中?如果它是本地文件,则第二篇帖子中的ircmaxell已经回复了你。您也可以使用互斥锁执行此操作 - 信号量函数。另一个解决方案是使用MySQL MyISAM表存储统计信息并使用类似update info_table set value = value + 1的内容。它应该锁定表,并序列化您的请求,您将没有任何问题。

答案 2 :(得分:0)

是的,因为PHP由Apache运行,而Apache可以组织执行线程,因为它认为最好(参见各种工作者模型)。因此,如果您想一次访问一个资源,您可以锁定一个文件(例如,如果您正在处理cron作业,这是好的),或者您依赖于数据库事务机制,ACID功能和数据库资源锁定,如果你正在处理数据。

答案 3 :(得分:0)

我最近使用PHP的flock函数创建了自己的互斥锁类机制的简单实现。当然,下面的代码可以改进,但适用于大多数用例。

function mutex_lock($id, $wait=10)
{
  $resource = fopen(storage_path("app/$id.lck"),"w");

  $lock = false;
  for($i = 0; $i < $wait && !($lock = flock($resource,LOCK_EX|LOCK_NB)); $i++)
  {
    sleep(1);
  }

  if(!$lock)
  {
    trigger_error("Not able to create a lock in $wait seconds");
  }

  return $resource;
}

function mutex_unlock($id, $resource)
{
  $result = flock($resource,LOCK_UN);
  fclose($resource);

  @unlink(storage_path("app/$id.lck"));

  return $result;
}

答案 4 :(得分:-2)

PHP不支持多线程,每个请求(因此每个PHP脚本)只能在一个线程中执行(甚至进程,具体取决于您运行PHP的方式)。