Я использую shmop и pcntl exts таким образом:
1. Вилка несколько ниток
2. Откройте сегмент разделяемой памяти одним и тем же ключом во всех разветвленных нитях и в главном потоке.
3. Запись / чтение в / из сегмента.
4. Удалите и создайте сегмент с его оригинальным именем большего размера.
Иногда мой код работает правильно, и все потоки меняют значения, чтобы другие потоки могли использовать эти значения. Но в большинстве случаев потоки работают так: «нет сегмента с указанным идентификатором». Хотя вышеупомянутые жалобы ясно показывают, что в одном из потоков уже создан сегмент с таким же идентификатором.
Чтобы обнаружить, что этот сегмент еще не создан, я пытаюсь открыть его с флагом ‘w’, и если он жалуется на несуществующий сегмент, я создаю его с флагом ‘c’.
Метод, который делает эту работу:
protected function open() {
// probe
echo '=== KEY IS: '.$this->key.PHP_EOL;
$this->memory = shmop_open($this->key, 'w', 0, 0);
if ($this->memory === false) {
echo getmypid().'Create segment'.PHP_EOL;
$this->memory = shmop_open($this->key, 'c', 0666, strlen(serialize($this->initialValue)));
} else {
echo getmypid().'Open segment'.PHP_EOL;
}
}
Мой вывод здесь:
I am child: 6370
...
=== KEY IS: 1895898008
PHP Warning: shmop_open(): unable to attach or create shared memory segment in /home/debian/MiniThreader/src/CommonStorage.php on line 90
...
I am child: 6369
...
I am child: 6368
...
6370Create segment
Expanding size from 6 to 17
New size is 17
...
=== KEY IS: 1895898008
6369Open segment
...
Expanding size from 17 to 28
...
=== KEY IS: 1895898008
6368Open segment
...
Expanding size from 28 to 39
New size is 39
...
I am child: 6367
...
=== KEY IS: 1895898008
PHP Warning: shmop_open(): unable to attach or create shared memory segment in /home/debian/MiniThreader/src/CommonStorage.php on line 90
6367Create segment
...
Expanding size from 6 to 17
New size is 17
...
=== KEY IS: 1895898008
PHP Warning: shmop_open(): unable to attach or create shared memory segment in /home/debian/MiniThreader/src/CommonStorage.php on line 90
6366Create segment
string(6) ""
В этом коде все потоки пытаются добавить свой идентификатор процесса в массив и увеличивают его при необходимости.
Итак, мой вопрос: почему иногда потоки не могут работать должным образом с общими сегментами, и какова природа этого поведения на более низком уровне?
И да, я использую семафор для предотвращения одновременного расширения:
protected function expand($newsize) {
sem_acquire($this->sizeSemaphore);
shmop_delete($this->memory);
$this->memory = shmop_open($this->key, 'c', 0644, $newsize);
sem_release($this->sizeSemaphore);
}
Этот вопрос не о памяти. Деструкторы (__destruct) является ответом.
Для тех, кто сталкивался с такими же проблемами с общей памятью или чем-то еще, рассмотрите возможность переписать ваши деструкторы, которые могут удалять данные, прежде чем вы действительно захотите это сделать.
В моем случае класс, который работает с сегментом памяти, имел код в деструкторе, который удаляет сегмент памяти. Но это действие предназначено только для основного потока.
Других решений пока нет …