У меня возникают проблемы с тем, как правильно обрабатывать создание дочернего процесса из многопоточной программы, которая использует Boost Asio многопоточным способом.
Если я правильно понимаю, способ запуска дочернего процесса в мире Unix - вызвать fork()
, а затем exec*()
. Кроме того, если я правильно понимаю, вызов fork()
будет дублировать все дескрипторы файлов и т.д., И они должны быть закрыты в дочернем процессе, если они не помечены как FD_CLOEXEC
(и тем самым атомарно закрываются при вызове exec*()
).
Boost Asio требует уведомления, когда fork()
вызывается для правильной работы, вызывая notify_fork()
. Однако в многопоточной программе это создает несколько проблем:
-
Сокеты по умолчанию унаследованы дочерними процессами, если я правильно понимаю. Они могут быть установлены в
SOCK_CLOEXEC
, но не непосредственно при создании *, что приводит к временному окну, если дочерний процесс создается из другого потока. -
notify_fork()
требует, чтобы ни один другой поток не вызывал какую-либо другую функциюio_service
, ни любую функцию на любом другом объекте ввода-вывода, связанного сio_service
. Это на самом деле не представляется возможным - ведь вся программа многопоточна по какой-то причине. -
Если я правильно понимаю, любой вызов функции между
fork()
иexec*()
должен быть безопасным для асинхронного сигнала (см.fork()
documentation), Документация о том, что вызовnotify_fork()
является безопасным для асинхронного сигнала, отсутствует. На самом деле, если я смотрю на исходный код Boost Asio (по крайней мере, в версии 1.54), могут быть вызовы pthread_mutex_lock, которые не являются безопасными для асинхронного сигнала если я правильно понимаю (см. Концепции сигналов, есть и другие вызовы, которые не входят в белый список).
Проблема №1 Возможно, я обойдусь, отделив создание дочерних процессов и сокетов + файлов, чтобы я мог гарантировать, что в окне между создаваемым сокетом и настройкой SOCK_CLOEXEC
не создается дочерний процесс. Проблема №2 сложнее, мне, вероятно, нужно будет убедиться, что все потоки обработчика asio остановлены, разворачивают вилку, а затем снова воссоздают их, что в лучшем случае является отличным, и действительно очень плохо в худшем случае (как насчет моих ожидающих таймеров?). Проблема № 3, похоже, делает это совершенно невозможным для правильного использования.
Как правильно использовать Boost Asio в многопоточной программе вместе с fork()
+ exec*()
?
... или я "раздвоен"?
Пожалуйста, дайте мне знать, если я неправильно понял какие-либо фундаментальные концепции (я поднимаюсь на программирование Windows, а не на * nix...).
Изменить:
* - На самом деле можно создать сокеты с SOCK_CLOEXEC
, установленными непосредственно в Linux, доступными с версии 2.6.27 (см. socket()
documentation). В Windows соответствующий флаг WSA_FLAG_NO_HANDLE_INHERIT
доступен с Windows 7 SP 1/Windows Server 2008 R2 SP 1 (см. WSASocket()
документация). OS X, похоже, не поддерживает это.