Переиспользование PID и сигналы
Thread управляет процессом через хэндл proc_open;
Signal — через «голый» PID. Именно эта разница объясняет, почему один безопасен
для управления жизненным циклом, а другой требует осторожности.
Почему Thread надёжен
Thread никогда не шлёт сигнал «сырому» числу вслепую. isAlive(), join() и каждый метод
сигнала проверяют хэндл proc_open через proc_get_status, который привязан именно к тому
дочернему процессу, что породил родитель. Когда этот процесс завершается и его пожинают, хэндл
знает об этом — нет окна, в котором хэндл мог бы указывать на другой процесс.
Почему «сырые» PID рискованны
Signal вызывает posix_kill($pid, ...) для числа, которое вы передали. PID — это
конечный, переиспользуемый ресурс: как только процесс завершается и его пожинают, ОС вольна
отдать его номер совершенно постороннему процессу. Поэтому PID, который вы захватили мгновение
назад, к моменту отправки сигнала может принадлежать чему-то совсем другому — и ваш
SIGTERM/SIGKILL попадёт не в ту цель.
Поэтому Signal задокументирован как «только свежие PID», и поэтому управление жизненным циклом
должно идти через Thread.
Тонкость с зомби
Внутри isProcessRunning() есть более острый угол. Зомби (состояние Z) — это процесс,
который уже завершился, но ещё не пожат родителем. Зомби всё ещё отвечает на
posix_kill($pid, 0) — проба возвращает «существует», хотя процесс не может выполнять работу
и должен считаться исчезнувшим.
Поэтому isProcessRunning() не ограничивается пробой. Убедившись, что PID отвечает, он проверяет
состояние процесса и считает зомби не работающим:
- Linux — читает
/proc/<pid>/statusи ищет^State:\s+Z. - macOS / BSD — выполняет
ps -o state= -p <pid>(с приведением$pidкint, так что инъекции в shell нет) и проверяет ведущийZ.
posix_kill(pid, 0) → false → не работает
→ true, состояние Z → не работает (зомби)
→ true, живой → работаетПрактическое правило
Используйте методы Thread, чтобы
останавливать и дожидаться работы, которую вы запустили. Берите Signal только с
PID, полученным непосредственно перед вызовом — например, при пожинании известного, ещё живого
дочернего процесса.
Связанное
- Сигналы и коды выхода — справочник по сигналам
- Корректное завершение — безопасная остановка работы
- Справочник API — методы
Signal