php - 在 RAII 中删除共享内存和信号量的正确策略,如 php 类

标签 php linux semaphore shared-memory pcntl

什么时候会出现这种情况?

如果您使用共享内存和信号量进行进程间锁定(使用 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);
         }
     }
     ....
}

所以,问题是

  1. 有没有办法在 php 中使用 IPC_RMID?
  2. 在这种情况下应该使用什么策略?仅在主进程中销毁?其他情况?

最佳答案

我检查了当前 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
        }
    }
}

但请注意 destructor is NOT executed in some circuumstances .

关于php - 在 RAII 中删除共享内存和信号量的正确策略,如 php 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23487723/

相关文章:

php - ERROR 过滤输入中的坏词并保存到 SQL

python - Linux如何编程,例如bash 或 python 脚本,知道它是如何启动的 : from command line or interactive GUI?

linux - 如何使用 yocto 食谱为 "configure"提供选项?

php - "Notice: Undefined variable"、 "Notice: Undefined index"、 "Warning: Undefined array key"和 "Notice: Undefined offset"使用 PHP

php - 如何保存响应式菜单打开/关闭值?

java - 无法使用 JWT 将文件上传到盒子 - curl : (26) failed creating formpost data

没有同步的Java等待/通知实现

c - 确保 child 在 parent 结束之前完成

c - 多请求单响应同步

php - 如何通过用户界面设置php项目来安装数据库