PHP互斥(互斥)

问题描述 投票:20回答:5

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

这个页面讨论了在硬盘上打开文件!!

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

可以用一个令人愉快的消息来安慰我吗?

编辑:

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

究竟我想要做什么

由ircmaxell提问。 这是故事:

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

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

而已。

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

可能解决方案

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

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

php mutex mutual-exclusion
5个回答
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一起使用,那么它取决于worker类型:

  1. mpm_worker将是多进程和多线程,具有由ServerLimit变量指定的进程数。
  2. prefork将是多进程的
  3. perchild也将是多进程的

编辑:回答您的第二个编辑问题:

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

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
投票

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


0
投票

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


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;
}

-2
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.