何时出现这种情况?
如果您使用共享内存和信号量进行interpocess锁定(使用pcntl extension),您应该关心信号量和共享内存段生命周期。例如,您编写backgroud worker应用程序并使用master和some child(forked)进程进行作业处理。使用共享内存和信号量在它们之间进行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);
}
}
....
}
不是很好的选择 - 在分叉之后我们在父母和子进程中有一个实例。其中任何一个的析构函数都会破坏信号量。
为什么重要
大多数Linux系统都限制共享内存计数的信号量。如果你有应用程序应该创建和删除信号量的许多共享内存段,你不能等待它在进程关闭时自动释放。
问题
使用с
您可以IPC_RMID
使用shmctl - 它标记要删除的细分。当当前附加到段的最后一个进程已正确分离它时,会发生实际的删除。当然,如果当前没有任何进程附加到该段,则立即删除。它的工作原理就像简单的参考计数器。但是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);
}
}
....
}
所以,问题是
答案 0 :(得分:1)
我检查了当前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
}
}
}