为什么PHP的sem_acquire会阻止程序执行?

时间:2014-05-08 06:10:46

标签: php semaphore shared-memory

我正在开发一个在gentoo Linux上运行的非常大且复杂的PHP项目,这显然存在PHP信号量的一些问题。由于项目的规模和复杂性,我无法发布代码。我也无法提供再现问题的工作示例。它可能是由于程序的复杂性以非威慑方式引起的。

问题在于:PHP代码正在尝试使用信号量写入和读取共享内存。在产生问题的情况下,执行以下操作:

  1. 在时间006.68,PHP 4.4.9执行以下代码,将5个字节的数据写入共享内存,$iVarKey的值为2010147023

    sem_acquire($this->rSemaphore);
    shm_put_var($this->rShm, $iVarKey, $mVar);
    sem_release($this->rSemaphore);
    

    此操作在006.69

  2. 时结束
  3. 在时间006.77,PHP 5.2.10执行以下代码,从共享内存中读取5个字节的数据,$iVarKey的值为622679600:

    sem_acquire($this->rSemaphore);
    $mVar = shm_get_var($this->rShm,$iVarKey);
    sem_release($this->rSemaphore);
    

    此操作在006.78

  4. 时结束
  5. 在时间016.01,PHP 5.2.10(与#2中的代码行相同)执行以下代码,从共享内存中读取5个字节的数据,$iVarKey的值为2010147023 (与#1相同):

    sem_acquire($this->rSemaphore);
    $mVar = shm_get_var($this->rShm,$iVarKey);
    sem_release($this->rSemaphore);
    

    此操作现在大约需要2分钟,尽管具有相同$iVarKey的资源/信号量已提前约10秒发布。在此期间没有访问共享内存,因为我已经确定每次调用sem_acquire

  6. sem_acquire如何阻止程序执行,尽管它不应该。也许这是版本4.4.9 / 5.2.10中的错误?有没有人看起来像类似的东西?有解决方法吗?我可以做些什么来进一步投资这个问题吗?

    我真的很感谢这个问题的帮助!

    备注

    • 如果您需要其他信息,我会尝试提供
    • 请不要对PHP4或两个PHP版本的并行使用发表评论和评论。
    • 如果有人认为这个问题不属于此,请提供指导。

    其他信息:   - 我已经检查了sem_release的每次通话,但似乎没有人回复FALSE。因此,我的问题并非来自失败的释放。   - 当系统阻塞时,ipcs -s返回以下输出,与系统未阻塞时相同

        ------ Semaphore Arrays --------
        key        semid      owner      perms      nsems     
        0x000f4240 0          root      666        3         
        0x00000001 32769      root      666        3         
        0x00000000 65538      apache    600        1 
    
    • 阻止信号量的sem_get()调用是

      $this->rSemaphore = sem_get(1000000,1,0666,1);
      
    • 涉及ftok的唯一电话似乎永远不会被调用。

1 个答案:

答案 0 :(得分:2)

您的代码假定始终获取信号量,这可能不是真的。试试这个

if(sem_acquire($this->rSemaphore)) {
    $mVar = shm_get_var($this->rShm,$iVarKey);
    if(!sem_release($this->rSemaphore)) {
      //log error
    }
}
else {
    //log error
}

一种可能的解决方法是使用flock()而不是信号量函数。缺点是flock()较慢,但根据您的使用情况,它可能足够快

$file = "/tmp/my_semaphore";
$fp = fopen($file,"r+");

if(flock($fp, LOCK_EX)) { // wait/acquire lock
    shm_put_var($this->rShm, $iVarKey, $mVar);
    if(!flock($fp, LOCK_UN)) { //release file lock
      //log error
    }
}
else {
    //something went wrong, unable to attain lock
}