Como lidar com fork () corretamente com boost :: asio em um programa multithread?
Estou tendo problemas para entender como lidar corretamente com a criação de um processo filho a partir de um programa multithread que usa o Boost Asio de uma maneira multithread.
Se bem entendi, a maneira de iniciar um processo filho no mundo Unix é chamarfork()
seguido por umexec*()
. Além disso, se eu entendi direito, chamandofork()
duplicará todos os descritores de arquivos e assim por diante, e estes precisam ser fechadosno processo filho a menos que marcado comoFD_CLOEXEC
(e, portanto, sendo atomicamente fechado ao chamarexec*()
)
O Boost Asio precisa ser notificado quandofork()
é chamado para operar corretamente chamandonotify_fork()
. No entanto, em um programa multithread, isso cria vários problemas:
Por padrão, os soquetes são herdados por processos filho, se bem entendi. Eles podem ser configurados paraSOCK_CLOEXEC
- mas não diretamente na criação*, levando a uma janela de tempo se um processo filho estiver sendo criado a partir de outro encadeamento.
notify_fork()
requer que nenhuma outra chamada de threadqualquer outroio_service
funçãonemqualquer função em qualquer outro objeto de E / S associado aoio_service
. Isso realmente não parece viável - afinal, o programa é multithread por um motivo.
Se bem entendi, qualquer chamada de função feita entrefork()
eexec*()
precisa ser seguro para sinal assíncrono (consultefork()
documentação) Não há documentação donotify_fork()
chamada sendo sinal assíncrono seguro. De fato, se eu olhar o código fonte do Boost Asio (pelo menos na versão 1.54), pode haver chamadas parapthread_mutex_lock, qual énão sinal assíncrono seguro se eu entendi corretamente (consulteConceitos de Sinal, há também outras chamadas que não estão na lista branca).
Problema nº 1 Provavelmente, posso resolver a questão separando a criação de processos filho e sockets + arquivos, para garantir que nenhum processo filho seja criado na janela entre um soquete sendo criado e a configuraçãoSOCK_CLOEXEC
. A edição nº 2 é mais complicada, eu provavelmente precisaria me certificar de quetudo os threads do manipulador asio estão parados, faça a bifurcação e depois os recrie novamente, o que é maré na melhor das hipóteses e realmente muito ruim na pior (e meus temporizadores pendentes ??). O problema nº 3 parece impossibilitar o uso correto.
Como uso corretamente o Boost Asio em um programa multithread junto comfork()
+ exec*()
? ... ou estou "bifurcada"?
Por favor, deixe-me saber se eu entendi mal algum conceito fundamental (sou educado em programação para Windows, não * nix ...).
Edit: * - Na verdade é possível criar soquetes comSOCK_CLOEXEC
configurado diretamente no Linux, disponível desde 2.6.27 (consultesocket()
documentação) No Windows, o sinalizador correspondenteWSA_FLAG_NO_HANDLE_INHERIT
está disponível desde o Windows 7 SP 1 / Windows Server 2008 R2 SP 1 (consulteWSASocket()
documentação) O OS X parece não suportar isso.