PHP Conference Japan 2024

sem_acquire

(PHP 4, PHP 5, PHP 7, PHP 8)

sem_acquire获取信号量

描述

sem_acquire(SysvSemaphore $semaphore, bool $non_blocking = false): bool

sem_acquire() 默认情况下会阻塞(如有必要),直到可以获取信号量。尝试获取它已经获取的信号量的进程,如果获取信号量会导致其信号量最大数量超出,则会永远阻塞。

处理请求后,进程获取但未显式释放的任何信号量将自动释放,并会生成警告。

参数

semaphore

semaphore 是从 sem_get() 获取的信号量。

non_blocking

指定进程是否不应等待获取信号量。如果设置为 true,如果无法立即获取信号量,则调用将立即返回 false

返回值

成功时返回 true,失败时返回 false

变更日志

版本 描述
8.0.0 semaphore 现在期望一个 SysvSemaphore 实例;以前,期望一个 resource

参见

添加注释

用户贡献的笔记 7 条笔记

gladd at trash dot eris dot qinetiq dot com
20 年前
澄清一下上面所说的“进程”的意思

在 Apache Web 服务器上,许多 PHP 请求将在同一个进程空间中执行,因为它具有多线程功能。但是,脚本获取和获取的任何信号量,如果没有释放和删除,PHP 解释器在每次脚本终止时仍然会自动清理它们。

在发送电子邮件之前删除任何垃圾!
Pinky
12 年前
sem_acquire() 是阻塞的,这意味着使用相同信号量的后续调用将无限期地阻塞,直到信号量被释放。这确保了序列化,但如果您只想检查是否应该继续,则它不太实用。不幸的是,PHP 还没有支持任何以非阻塞方式查询信号量状态的方法。

使用共享内存(shm_ 函数)手动构建这样的机制似乎是可能的。但是,请注意,这并非易事,最终也无济于事。例如,您不能简单地选择一个共享内存变量,存储信号量键并查询它。这样的操作是非事务性和非原子的,即两个或多个并行进程有可能在其中一个设法将其标记为“已锁定”之前,都从共享内存变量中读取“未锁定”。您必须使用(阻塞)信号量来序列化对共享内存变量的访问,从而重新创建您试图解决的问题。

换句话说,如果非阻塞查询对您至关重要,则您需要请求 PHP 设计师解决此问题,或者选择其他机制来执行锁定,一种已经具有此功能的机制。
Sander Backus
11 年前
请注意,当您重置 $sem_identifier 时,信号量将不再阻塞!

此代码不起作用
$key = ftok(__FILE__,'m');
$a = sem_get($key);
sem_acquire($a);
$a = false;

而这个有效

$key = ftok(__FILE__,'m');
$a = sem_get($key);
sem_acquire($a);
//$a = false;

所以:为您的标识符使用唯一的变量名!
arjuna w
12 年前
在我的测试中,sem_acquire() 比 flock() 快 150 倍。
Ben
4 年前
我最近不得不使用信号量来避免同时运行数据库更新。

为了测试它,我在同一台桌面上使用了两个浏览器窗口(Chrome)。

在这种情况下,信号量没有按预期工作。
同样,文件上的 flock 也没有按预期工作。

从命令行运行脚本按预期工作。

一旦我使用了两个不同的浏览器,一个在我的桌面上,另一个在虚拟机中,它就可以按预期工作了。

希望这可以帮助任何人避免在此主题上进行奇怪的调试会话……
anatoliy at ukhvanovy dot name
9 年前
如果您需要非阻塞信号量,以下是如何实现它的示例。使用共享内存变量来标记是否存在锁,然后在针对该变量的操作周围使用信号量。我将我的共享变量称为“token”。

<?php
echo '<pre>';

$resourceSemaphore = sem_get(7);
$tokenSemaphore = sem_get(8);
$tokenValue = shm_attach(9, 100);

function
myEcho($v) {
echo
microtime() . ' ' . $v . "\n";
}

// sem_remove($resourceSemaphore);
// sem_remove($tokenSemaphore);
// exit();

function try_lock() {
global
$resourceSemaphore, $tokenSemaphore, $tokenValue;
myEcho('begin try_lock()');
myEcho('acquire token semaphore');
sem_acquire($tokenSemaphore);
myEcho(' token semaphore acquired');
$tmp = shm_get_var($tokenValue, 6);
myEcho(' token value: ' . var_export($tmp, true));
$exit = $tmp;
if (!
$exit) {
$tmp = shm_put_var($tokenValue, 6, true);
$tmp = shm_get_var($tokenValue, 6);
myEcho(' token new value: ' . var_export($tmp, true));
}
myEcho('release token semaphore');
sem_release($tokenSemaphore);
if (
$exit) return false;
myEcho('acquire resource semaphore');
sem_acquire($resourceSemaphore);
myEcho(' resource semaphore acquired');
return
true;
}

function
release() {
global
$resourceSemaphore, $tokenSemaphore, $tokenValue;
myEcho('release resource semaphore');
sem_release($resourceSemaphore);
myEcho('acquire token semaphore');
sem_acquire($tokenSemaphore);
myEcho(' token semaphore acquired');
$tmp = shm_get_var($tokenValue, 6);
myEcho(' token value: ' . var_export($tmp, true));
$tmp = shm_put_var($tokenValue, 6, false);
$tmp = shm_get_var($tokenValue, 6);
myEcho(' token new value: ' . var_export($tmp, true));
myEcho('release token semaphore');
sem_release($tokenSemaphore);
}

for (
$triesLeft = 5; $triesLeft > 0 && !try_lock(); $triesLeft--) {
myEcho('failed to acquire resource');
myEcho('wait for 1 sec');
sleep(1);
myEcho('try again');
}
myEcho(' access the resource for 4 sec');
//粘贴此处你的代码,访问你的资源
sleep(4);
release();
myEcho('the end');
?>
当我并行执行此脚本两个实例时,我得到以下输出
-------(第一个实例)----------------------------------------
... 482 begin try_lock()
... 482 acquire token semaphore
... 482 token semaphore acquired
... 482 token value: false
... 482 token new value: true
... 482 release token semaphore
... 482 acquire resource semaphore
... 482 resource semaphore acquired
... 482 access the resource for 4 sec
... 486 release resource semaphore
... 486 acquire token semaphore
... 486 token semaphore acquired
... 486 token value: true
... 486 token new value: false
... 486 release token semaphore
... 486 the end
-------(第二个实例)----------------------------------------
... 485 begin try_lock()
... 485 acquire token semaphore
... 485 token semaphore acquired
... 485 token value: true
... 485 release token semaphore
... 485 failed to acquire resource
... 485 wait for 1 sec
...
... 486 wait for 1 sec
... 487 try again
... 487 begin try_lock()
... 487 acquire token semaphore
... 487 token semaphore acquired
... 487 token value: false
... 487 token new value: true
... 487 release token semaphore
... 487 acquire resource semaphore
... 487 resource semaphore acquired
... 487 access the resource for 4 sec
... 491 release resource semaphore
... 491 acquire token semaphore
... 491 token semaphore acquired
... 491 token value: true
... 491 token new value: false
... 491 release token semaphore
... 491 the end
anatoliy at ukhvanovy dot name
9 年前
不幸的是,PHP 目前不支持非阻塞信号量。

如果需要类似的功能,您可以将信号量与共享内存一起使用来创建自己的非阻塞锁机制。

使用共享内存变量来标记是否存在锁,然后在对该变量的操作周围使用信号量。
To Top