什么情况下会出现这种情况?
如果您正在使用共享内存和信号量进行进程间锁定(使用 pcntl 扩展),则应关注信号量和共享内存段的生命周期。例如,您正在编写后台工作程序,并使用主进程和一些子进程(已分叉)来处理作业。在它们之间使用共享内存和信号量是个好主意。而像 shm_xxx 和 sem_xxx php 函数周围的 RAII 类包装器看起来也是个好主意。
示例
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系统的信号量共享内存数量都有限制。 如果您有应用程序需要创建和删除许多信号量的共享内存段,则无法等待它在进程关闭时自动释放。
问题
使用c
,您可以使用带有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);
}
}
....
}
问题是:
- 是否有任何方法在 PHP 中使用 IPC_RMID?
- 在这种情况下应该使用什么策略?只在主进程中销毁?还是其他情况需要考虑?