Почему PHP sem_acquire блокирует выполнение программы?

Я работаю над очень большим и сложным проектом PHP, работающим на gentoo Linux, который, очевидно, имеет некоторые проблемы с семафорами PHP. Из-за размера и сложности проекта я не могу опубликовать код. Я также не могу представить рабочий пример, который воспроизводит проблему. Это может быть вызвано сложностью программы неопределенным образом.

Вот проблема: PHP-код пытается писать и читать в/из разделяемой памяти с помощью семафоров. В случае возникновения проблемы выполняются следующие действия:

  • В момент 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

  • В момент 006.77 PHP PHP 5.2.10 выполняется для чтения 5 байтов данных из разделяемой памяти, причем $iVarKey имеет значение 622679600:

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

    Это действие завершается в момент 006.78

  • В момент 016.01 PHP 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!

Как возможно, что 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

Ваш код предполагает, что семафор всегда приобретается, что может быть неверным. Попробуйте это

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
}