php PHP互斥(互斥)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2921469/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
PHP mutual exclusion (mutex)
提问by Poni
Read some texts about locking in PHP.
They all, mainly, direct to http://php.net/manual/en/function.flock.php.
阅读一些关于在 PHP 中锁定的文本。
它们都主要指向http://php.net/manual/en/function.flock.php。
This page talks about opening a file on the hard-disk!!
本页讨论在硬盘上打开文件!!
Is it really so? I mean, this makes locking really expensive - it means each time I want to lock I'll have to access the hard-disk )=
真的是这样吗?我的意思是,这使得锁定非常昂贵 - 这意味着每次我想要锁定我都必须访问硬盘 )=
Can anymore comfort me with a delightful news?
能不能再用一个令人愉快的消息来安慰我?
Edit:
编辑:
Due to some replies I've got here, I want to ask this;
My script will run only by one thread, or several? Because if it's by one then I obviously don't need a mutex. Is there a concise answer?
由于我在这里得到的一些答复,我想问这个;
我的脚本只能由一个线程运行,还是由多个线程运行?因为如果是一个,那么我显然不需要互斥锁。有简洁的答案吗?
What exactly I'm trying to do
我到底想做什么
Asked by ircmaxell.
This is the story:
由 ircmaxell 询问。
这是故事:
I have two ftp servers. I want to be able to show at my website how many online users are online.
So, I thought that these ftp servers will "POST" their stats to a certain PHP script page. Let's assume that the URL of this page is "http://mydomain.com/update.php".
我有两个 ftp 服务器。我希望能够在我的网站上显示有多少在线用户在线。
所以,我认为这些 ftp 服务器会将它们的统计信息“发布”到某个 PHP 脚本页面。让我们假设这个页面的 URL 是“ http://mydomain.com/update.php”。
On the website's main page ("http://mydomain.com/index.php") I will display the cumulative statistics (online users).
在网站的主页(“ http://mydomain.com/index.php”)上,我将显示累积统计数据(在线用户)。
That's it.
就是这样。
My problem is that I'm not sure if, when one ftp server updates his stats while another does it too, the info will get mixed.
Like when multi-threading; Two threads increase some "int" variable at the same time. It will not happen as expected unless you sync between them.
So, will I have a problem? Yes, no, maybe?
我的问题是,我不确定当一个 ftp 服务器更新他的统计数据而另一个服务器也更新时,信息是否会混淆。
就像多线程时一样;两个线程同时增加一些“int”变量。除非您在它们之间同步,否则它不会按预期发生。
那么,我会有问题吗?是的,不,也许?
Possible solution
可能的解决方案
Thinking hard about it all day long, I have an idea here and I want you to give your opinion.
As said these ftp servers will post their stats, once every 60sec.
I'm thinking about having this file "stats.php".
It will be included at the updating script that the ftp servers go to ("update.php") and at the "index.php" page where visitors see how many users are online.
Now, when an ftp server updates, the script at "update.php" will modify "stats.php" with the new cumulative statistics.
First it will read the stats included at "stats.php", then accumulate, and then rewrite that file.
想了半天,有一个想法,希望大家给点意见。
如上所述,这些 ftp 服务器将每 60 秒发布一次他们的统计信息。
我正在考虑拥有这个文件“stats.php”。
它将包含在 ftp 服务器访问的更新脚本(“update.php”)和“index.php”页面中,访问者可以在其中查看有多少用户在线。
现在,当 ftp 服务器更新时,“update.php”中的脚本将使用新的累积统计信息修改“stats.php”。
首先它将读取包含在“stats.php”中的统计信息,然后累积,然后重写该文件。
If I'm not mistaken PHP will detect that the file ("stats.php") is changed and load the new one. Correct?
如果我没记错的话,PHP 会检测到文件(“stats.php”)已更改并加载新文件。正确的?
回答by ircmaxell
Well, most of PHP runs in a different process space (there are few threading implementations). The easy one is flock. It's guaranteed to work on all platforms.
好吧,大多数 PHP 运行在不同的进程空间中(很少有线程实现)。最简单的就是羊群。它保证适用于所有平台。
However, if you compile in support, you can use a few other things such as the Semaphore extension. (Compile PHP with --enable-sysvsem). Then, you can do something like (note, sem_acquire() should block. But if it can't for some reason, it will return false):
但是,如果您在支持中编译,则可以使用其他一些东西,例如 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...
}
The other options that you have, are MySQL user level locksGET_LOCK('name', 'timeout'), or creating your own using something like APC or XCache (Note, this wouldn't be a true lock, since race conditions could be created where someone else gets a lock between your check and acceptance of the lock).
您拥有的其他选项是 MySQL用户级锁GET_LOCK('name', 'timeout'),或者使用诸如 APC 或 XCache 之类的东西创建自己的锁(注意,这不是真正的锁,因为可能会在其他人在您的检查之间获得锁的情况下创建竞争条件并接受锁定)。
Edit: To answer your edited question:
编辑:要回答您编辑的问题:
It all depends on your server configuration. PHP May be run multi-threaded (where each request is served by a different thread), or it may be run multi-process (where each request is served by a different process). It all depends on your server configuration...
这一切都取决于您的服务器配置。PHP 可以多线程运行(每个请求由不同的线程提供服务),也可以多进程运行(每个请求由不同的进程提供服务)。这完全取决于您的服务器配置...
It's VERY rare that PHP will serve all requests serially, with only one process (and one thread) serving all requests. If you're using CGI, then it's multi-process by default. If you're using FastCGI, it's likely multi-process and multi-thread. If you're using mod_php with Apache, then it depends on the worker type:
PHP 很少会串行处理所有请求,只有一个进程(和一个线程)处理所有请求。如果您使用的是 CGI,则默认情况下它是多进程的。如果您使用的是 FastCGI,它可能是多进程和多线程的。如果您在 Apache 中使用 mod_php,则这取决于工作程序类型:
- mpm_worker will be both multi-process and multi-thread, with the number of processes dictated by the ServerLimit variable.
- prefork will be multi-process
- perchild will be multi-process as well
- mpm_worker 将是多进程和多线程的,进程数由 ServerLimit 变量决定。
- prefork 将是多进程的
- perchild 也将是多进程的
Edit: To answer your second edited question:
编辑:要回答您编辑的第二个问题:
It's quite easy. Store it in a file:
这很容易。将其存储在一个文件中:
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;
}
回答by Milen Boev
The question is: Where will you store the stats that the FTP servers are pushing with POST to your update.php file? If it's a local file, than ircmaxell in the second post has answered you. You can do this with a mutex as well - the semaphore functions. Another solution is to use MySQL MyISAM table to store the stats and use something like update info_table set value = value + 1. It should lock the table, and serialize your requests, and you will have no problems.
问题是:您将 FTP 服务器通过 POST 推送到您的 update.php 文件的统计信息存储在哪里?如果它是一个本地文件,那么第二篇文章中的 ircmaxell 已经回答了你。您也可以使用互斥锁来做到这一点 - 信号量函数。另一种解决方案是使用 MySQL MyISAM 表来存储统计信息并使用类似update info_table set value = value + 1. 它应该锁定表,并序列化您的请求,您将没有问题。
回答by Mark Baaijens
I recently created my own simple implementation of a mutex-like mechanism using the flock function of PHP. Of course the code below can be improved, but it is working for most use cases.
我最近使用 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;
}
回答by Palantir
Yes that's true, as PHP is run by Apache, and Apache can organize the threads of execution as it deems the best (see the various worker model). So if you want to access a resource one at a time, you either lock to a file (which is good if you are dealing with cron jobs for example), or you rely on database transaction mechanism, ACID features, and database resources locking, if you are dealing with data.
是的,这是真的,因为 PHP 由 Apache 运行,Apache 可以按照它认为最好的方式组织执行线程(请参阅各种工作线程模型)。因此,如果您想一次访问一个资源,要么锁定一个文件(例如,如果您正在处理 cron 作业,这很好),要么依赖数据库事务机制、ACID 特性和数据库资源锁定,如果您正在处理数据。
回答by Daff
PHP doesn't support multithreading, every request (and therefore every PHP script) will be executed in only one thread (or even process, depending on the way you run PHP).
PHP 不支持多线程,每个请求(因此每个 PHP 脚本)将仅在一个线程(甚至进程,取决于您运行 PHP 的方式)中执行。

