在RAII-like php类中使用共享内存和信号量删除的正确策略
这种情况何时发生? 如果您使用共享内存和信号量进行interprocess锁定(with),那么您应该关注信号量和共享内存段的生命周期。例如,您正在编写BackgroundWorker应用程序,并使用主进程和某些子进程(分叉)进行作业处理。在它们之间使用共享内存和信号量是IPC的好主意。而且在RAII-like php类中使用共享内存和信号量删除的正确策略,php,linux,semaphore,shared-memory,pcntl,Php,Linux,Semaphore,Shared Memory,Pcntl,这种情况何时发生? 如果您使用共享内存和信号量进行interprocess锁定(with),那么您应该关注信号量和共享内存段的生命周期。例如,您正在编写BackgroundWorker应用程序,并使用主进程和某些子进程(分叉)进行作业处理。在它们之间使用共享内存和信号量是IPC的好主意。而且RAII类似于围绕shm_xxx和sem_xxx php函数的类包装器看起来也是个好主意 示例 class Semaphore { private $file; private $sem
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系统对共享内存计数的信号量都有限制。如果您有一个应用程序,它应该创建和删除信号量的许多共享内存段,那么在进程关闭时自动释放它时,您就不能等待了
问题
使用c
可以与IPC\u 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);
}
}
....
}
所以,问题是
IPC\u RMID
未使用。但是,PHP使用semop()
,并使用它设置SEM\u UNDO
标志,以防设置了auto\u release
(请参阅)。但请注意,这在每个流程级别上都有效。所以,如果您使用PHP作为Apache模块,或FCGI或FPM,它可能无法按预期工作。不过,对于CLI来说,它应该可以很好地工作
对于清理,这取决于“主”是否最后终止
如果您不知道,您可以自己实现引用计数
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
}
}
}
类信号量
{
静态私有$m_referenceCount=0;
公共函数构造()
{
++self::$m_referenceCount;
//阿奎尔信号灯
}
公共函数_udestruct()
{
如果(--self::$m_referenceCount Yes,我的问题比其他实际的for CLI情况更重要。自制引用计数有一个关键问题-您应该确保引用递增/递减是原子操作。因此您应该有一些进程间锁来实现这一点。Yes?递增或递减整数(在本机大小下)当然是原子的!可能不是原子的是递减和比较操作。但即使不是原子的,它在某些情况下仍然可以可靠地工作:如果您先创建所有实例,然后在任何时候逐个删除它们,而不创建新实例,您将进行清理。可能两次或多次,但至少一次。Shi,我的意思是,原子联锁应该在一些单独的CLI进程中实现——简单情况下是主进程和一个从进程。PHP共享内存实现没有任何原子操作。因此,您应该自行进行锁定。这种锁定的基本实现是共享内存+信号量。但如何了解锁定对象的生命周期E