什么时候出现这种情况?
如果您使用共享内存和信号量进行进程间锁定(使用pcntl 扩展),您应该关心信号量和共享内存段生命周期。例如,您编写后台工作者应用程序并使用主进程和一些子(分叉)进程进行作业处理。在它们之间使用共享内存和信号量是 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 系统对共享内存计数的信号量都有限制。如果您的应用程序应该创建和删除信号量的许多共享内存段,那么您不能等待它在进程关闭时自动释放。
问题
使用с
您可以使用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?
- 在这种情况下应该使用什么策略?只在主进程中销毁?其他情况?