什么时候会出现这种情况?
如果您使用共享内存和信号量进行进程间锁定(使用 pcntl extension ),您应该关心信号量和共享内存段生命周期。例如,您编写后台 worker 应用程序并使用主进程和一些子( fork )进程进行作业处理。在它们之间使用共享内存和信号量是 IPC 的好主意。和 RAII
类似 shm_xxx 和 sem_xxx php 函数的类包装器看起来也是个好主意。
示例
class Semaphore
{
private $file;
private $sem;
public function __construct()
{
$this->file = tempnam(sys_get_temp_dir(), 's');
$semKey = ftok($this->file, 'a');
$this->sem = sem_get($semKey, 1); //auto_release = 1 by default
}
public function __destruct()
{
if (is_resource($this->sem) {
sem_remove($this->sem);
}
}
....
}
不是很好的选择 - 在 fork 之后,我们在父进程中有一个实例,在子进程中有一个实例。其中任何一个中的析构函数都会破坏信号量。
为什么重要
大多数 linux 系统对共享内存数量的信号量都有限制。如果您的应用程序应该创建和删除信号量的许多共享内存段,您就不能等待它在进程关闭时自动释放。
问题
使用 с
你可以使用 shmctl使用 IPC_RMID
- 它标记要删除的段。当当前附加到该段的最后一个进程已正确分离它时,实际删除本身就会发生。当然,如果当前没有进程附加到该段,删除似乎是立即的。它像简单的引用计数器一样工作。但是 php 没有实现 shmctl
。
另一种策略 - 仅在主进程的析构函数中销毁信号量:
class Semaphore
{
...
private $pid;
public function __construct()
{
$this->pid = getmypid();
...
}
public function __destruct()
{
if (is_resource($this->sem) && $this->pid === getmypid()) {
sem_remove($this->sem);
}
}
....
}
所以,问题是
- 有没有办法在 php 中使用 IPC_RMID?
- 在这种情况下应该使用什么策略?仅在主进程中销毁?其他情况?
最佳答案
我检查了当前 PHP source code IPC_RMID
未使用。然而,PHP 使用 semop()
和 SEM_UNDO
标志,以防 auto_release
(参见 PHP sem_get() manual)被设置。但请注意,这适用于每个进程级别。因此,如果您使用 PHP 作为 Apache 模块,或者 FCGI 或 FPM,它可能无法按预期工作。不过,它应该适用于 CLI。
对于您的清理,这取决于“master”是否最后终止。
如果你不知道,你可以自己实现引用计数。
class Semaphore
{
static private $m_referenceCount = 0;
public function __construct()
{
++self::$m_referenceCount;
// aquire semaphore
}
public function __destruct()
{
if (--self::$m_referenceCount <= 0) {
// clean up
}
}
}
关于php - 在 RAII 中删除共享内存和信号量的正确策略,如 php 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23487723/