Почему 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
}