На его веб - странице о с трюком собственной трубы , Dan Bernstein объясняет состояние гонки с select()
и сигналами, предлагает обходной путь и приходит к выводу , что
Конечно, правильно было бы
fork()
возвращать дескриптор файла, а не идентификатор процесса.
Что он подразумевает под этим - это что-то такое, что позволяет select()
дочерним процессам обрабатывать изменения своего состояния вместо того, чтобы использовать обработчик сигнала для получения уведомлений об этих изменениях состояния?
signals
file-descriptors
fork
Ласси
источник
источник
signalfd
и так было тогда?wait()
, были вещи, которые вы не могли сделать, поэтому кто-то изобрел SIGCHLD, но это была плохая работа. По моему опыту, и теперь, когда они существуют, посыпая красиво, блокирующаяwait3()
,wait4()
и / илиwaitpid()
звонки в ключевых местах (возможно , ваш основной цикл событий) является гораздо лучшей альтернативой.Ответы:
Проблема описана там, в вашем источнике,
select()
должна прерываться подобными сигналамиSIGCHLD
, но в некоторых случаях она работает не так хорошо. Таким образом, обходной путь должен иметь запись сигнала в канал, который затем отслеживаетсяselect()
. Просмотр файловых дескрипторов предназначенselect()
для решения этой проблемы.Обходной путь по существу превращает событие сигнала в событие дескриптора файла. Если бы
fork()
просто вернул fd во-первых, обходной путь не потребовался бы, так как этот fd, вероятно, мог бы затем использоваться непосредственно сselect()
.Так что да, ваше описание в последнем абзаце мне кажется правильным.
Другая причина того, что fd (или какой-либо другой вид дескриптора ядра) будет лучше, чем простой номер идентификатора процесса, заключается в том, что идентификаторы PID могут быть повторно использованы после смерти процесса. Это может быть проблемой в некоторых случаях при отправке сигналов процессам, возможно, невозможно будет точно знать, что процесс - это то, что вы думаете, а не другой, повторно использующий тот же PID. (Хотя я думаю, что это не должно быть проблемой при отправке сигналов дочернему процессу, так как родитель должен запустить дочерний процесс
wait()
для освобождения его PID.)источник
wait()
.clone
, который является фактическим системным вызовом, который вызывает fork в LInux. Флаг для включения этого называетсяCLONE_PIDFD
- см. Например lwn.net/Articles/784831 .Это просто размышления о том, что «было бы здорово, если бы Unix был спроектирован иначе, чем он есть».
Проблема с PID состоит в том, что они живут в глобальном пространстве имен, где их можно повторно использовать для другого процесса, и было бы неплохо, если бы
fork()
в родительском элементе возвращался какой-то дескриптор, который гарантированно всегда будет ссылаться на дочерний процесс, и что он может передаваться другим процессам через наследование или сокеты unix /SCM_RIGHTS
[1].Смотрите также обсуждение здесь для недавней попытки "исправить" это в Linux, включая добавление флага,
clone()
который заставит его возвращать pid-fd вместо PID.Но даже в этом случае это не устранит необходимость в этом хакерстве [2] или более совершенных интерфейсах, поскольку сигналы, уведомляющие родительский процесс о состоянии дочернего элемента, не единственные, которые вы хотели бы обработать в основном цикле. программы. К сожалению, такие вещи, как
epoll(7) + signalfd(2)
в Linux илиkqueue(2)
в BSD, не являются стандартными - единственный стандартный интерфейс (но не поддерживается в старых системах) намного хужеpselect(2)
.[1] Предотвращение повторного цикла PID к тому времени, когда
waitpid()
системный вызов возвратился и его возвращаемое значение использовалось, вероятно, может быть достигнуто в более новых системах с помощьюwaitid(.., WNOWAIT)
взамен.[2] Я бы не стал комментировать заявление ди-джея Бернштейна о том, что он его придумал (извините за апофазис ;-)).
источник
Бернштейн не дает большого контекста для этого замечания «Правильное дело», но я рискну предположить: наличие fork (2), возвращающего PID, несовместимо с open (2), creat (2) и т. Д., Возвращающими файловые дескрипторы. Остальная часть системы Unix могла бы выполнять манипулирование процессом с помощью файлового дескриптора, представляющего процесс, вместо PID. Существует системный вызов signalfd (2) , который позволяет несколько лучше взаимодействовать между сигналами и файловыми дескрипторами и показывает, что файловый дескриптор, представляющий процесс, может сработать.
источник
pidfd_open
в Linux, см., Например, lwn.net/Articles/789023