C ++: Como implementar um tempo limite para uma chamada de função arbitrária?
Pergunta
Eu preciso chamar uma função de biblioteca que às vezes não vai terminar dentro de um determinado tempo, infelizmente. Existe uma maneira de chamar a função, mas abort-lo se ele não terminar dentro de segundos n
?
Não posso modificar a função, então eu não posso colocar a condição abort para ele diretamente. Eu tenho que adicionar um tempo limite para a função externamente .
É talvez uma solução possível para iniciá-lo como um (boost) rosca, que pode, então, terminar depois de um certo tempo? Será que algo como isso funciona? Eu realmente acredito que a função é não thread-safe, mas isso não importa se eu executá-lo como o única único segmento, certo? Existem outros (melhor) soluções?
Solução
Você poderia gerar um boost::thread
para chamar a API:
boost::thread api_caller(::api_function, arg1, arg2);
if (api_caller.timed_join(boost::posix_time::milliseconds(500)))
{
// API call returned within 500ms
}
else
{
// API call timed out
}
Aumento não permite que você para matar o segmento de trabalho, no entanto. Neste exemplo, é só órfão.
Você vai ter que ser cuidadoso sobre o que chamada de API faz, porque nunca pode liberar recursos é adquirido.
Outras dicas
Eu acho que a única maneira segura de fazer isso seria a de gerar um separado sandbox processo que chama a função de biblioteca como um proxy para a sua aplicação. Você precisa implementar algum tipo de IPC entre seu aplicativo e o proxy. A implementação de um tempo limite ao ler a resposta IPC é então bastante trivial. Se a leitura falhar devido ao tempo limite, então você pode seguramente terminar o proxy sem arriscar a saúde de sua aplicação.
O que você está falando é normalmente chamado um sistema de "cão de guarda". O cão de guarda é, tipicamente, um segundo fio que verificações sobre o estado de todos os outros segmentos. A agência geralmente é configurado para ser executado periodicamente. Se nenhuma resposta foi recebida de outros tópicos, o cão de guarda pode notificar o usuário, ou mesmo matar o fio agressor se é possível fazê-lo com segurança (depende da sua aplicação).
O problema com tópicos é que alguns recursos que você não será capaz de libertar após o término fio. Se você não adquirir recursos que você tem que liberar, em seguida, ir com threads.
execution_monitor de Boost.Test faz o que quiser:
O problema é que, com uma solução in-process sem o apoio da função você acabar com o estado potencialmente inválido.
Exemplo:. Quando você terminar a thread enquanto uma alocação de memória está ocorrendo, sua pilha de processo pode ser corrompido
Assim que você pode encerrar a ligação, mas então você também tem que terminar o processo. Em muitos casos, as chances de efeitos colaterais destrutivos são pequenos, mas eu não apostaria meu cálculo sobre isso.
Você pode, como Ben Straub sugere, apenas órfão o tópico: colocá-lo em prioridade mais baixa e que partem para o infinito. Isso é, naturalmente, apenas uma solução limitada:. Se os ressources consome rosca (provável), que vai abrandar o sistema, também há um limite para threads por processo (geralmente devido a espaço de endereço para segmento de pilha)
Geralmente, eu prefiro a solução processo externo. Um padrão simples é esta:
de dados de escrita de entrada para um arquivo, inicie o processo externo com o arquivo como argumento. O processo externo escreve progresso (se houver) para um arquivo em disco que pode ser monitorado, e pode até permitir que o processo para retomar de onde começou. Os resultados são gravados no disco, e o processo pai pode ler-los.
Quando você terminar o processo, você ainda tem que lidar com a sincronização de acesso a Recursos externos (como arquivos), e como lidar com mutices abandonadas, arquivos escritos à meia etc. Mas é geralmente o caminho para uma solução robusta.
Vá com um processo órfão, lançá-lo e tempo de sua execução. Se ele é executado fora do tempo, invocar o OS para matá-lo.
Como evitar Conds corrida. neste padrão:
-
criar um arquivo para armazenar em args (claro, tudo é repassado como Vals). O processo órfão só é permitido para ler dados a partir deste arquivo.
-
O órfão processa os dados de entrada, cria um ficheiro de saída com valores de resultados e fecha-o.
-
Somente quando tudo é feito, órfão exclui o arquivo de entrada, um fato que os sinais do processo mestre que o trabalho foi feito.
Esta leitura escrita à metade problema arquivos, uma vez que o mestre primeiros avisos absense de arquivo de entrada evita, abre para ler o arquivo de saída, que é certamente concluída (porque foi fechado antes de eliminar entrada e pilhas de chamadas OS são sequenciais).
"Eu preciso chamar uma função de biblioteca que às vezes não vai terminar dentro de um determinado tempo, infelizmente. Existe uma maneira de chamar a função, mas abort-lo se ele não terminar dentro de n segundos?"
A resposta curta não é. Isso é geralmente o problema ... A chamada em si deve terminar em algum momento (implementação do seu próprio tempo limite), mas chamadas de bloqueio são geralmente problemas (por exemplo, gethostbyname ()), porque então cabe a sua (ou sistema) de tempo limite, não seu.
Assim, sempre que possível, tentar fazer o código em execução na saída de segmento limpa quando necessário - o próprio código deve detectar e tratar o erro. Pode enviar uma mensagem e / ou conjunto de estados de modo que o principal (ou aother) Rosca sabe o que se passou.
A preferência pessoal, em sistemas altamente disponíveis, eu como os meus tópicos girando frequentemente (não ocupado-locking embora) com limites de tempo específicos, chamando funções sem bloqueio, e com condições de saída precisas no lugar. A-específica fio global ou 'feito' variável faz o truque para uma saída limpa.