Como você lida com a limpeza quando o programa recebe um sinal de eliminação?
Por exemplo, há um aplicativo ao qual me conecto que deseja que qualquer aplicativo de terceiros (meu aplicativo) envie um finish
comando ao fazer logout. Qual é a melhor coisa a dizer para enviar esse finish
comando quando meu aplicativo for destruído com um kill -9
?
editar 1: kill -9 não pode ser capturado. Obrigado pessoal por me corrigir.
edição 2: Eu acho que este caso seria quando aquele chama apenas kill, que é o mesmo que ctrl-c
kill -9
significa para mim: "Vá embora, processo sujo, vá embora!", quando o processo cessará. Imediatamente.kill
não é o mesmo que Ctrl-C, poiskill
sem especificar qual sinal enviar enviará SIGTERM, enquanto Ctrl-C enviará SIGINT.Respostas:
É impossível para qualquer programa, em qualquer linguagem, lidar com um SIGKILL. Assim, sempre é possível encerrar um programa, mesmo que ele tenha bugs ou seja malicioso. Mas o SIGKILL não é o único meio de encerrar um programa. A outra é usar um SIGTERM. Os programas podem lidar com esse sinal. O programa deve controlar o sinal fazendo um desligamento controlado, mas rápido. Quando um computador é desligado, o estágio final do processo de desligamento envia a cada processo restante um SIGTERM, dá a esses processos alguns segundos de graça e, em seguida, envia um SIGKILL.
A maneira de lidar com isso para qualquer coisa outra que
kill -9
seria registrar um encerramento gancho. Se você puder usar ( SIGTERM ),kill -15
o gancho de desligamento funcionará. ( SIGINT )kill -2
FAZ com que o programa saia normalmente e execute os ganchos de desligamento.Tentei o seguinte programa de teste no OSX 10.6.3 e
kill -9
nele NÃO executei o gancho de desligamento, como esperado. Em umakill -15
ele FAZ executar o gancho de desligamento de cada vez.Não há nenhuma maneira de lidar com um
kill -9
em nenhum programa.A única opção real para lidar com um
kill -9
é fazer com que outro programa inspetor observe se seu programa principal vai embora ou use um script wrapper. Você poderia fazer isso com um script de shell que pesquisasse ops
comando à procura de seu programa na lista e agiria de acordo quando ele desaparecesse.fonte
Não são maneiras de lidar com os seus próprios sinais em determinadas JVMs - ver este artigo sobre o HotSpot JVM por exemplo.
Usando a
sun.misc.Signal.handle(Signal, SignalHandler)
chamada de método interna da Sun , você também pode registrar um manipulador de sinal, mas provavelmente não para sinais comoINT
ouTERM
como são usados pela JVM.Para ser capaz de lidar com qualquer sinal, você teria que pular da JVM para o território do sistema operacional.
O que geralmente faço para (por exemplo) detectar o encerramento anormal é iniciar minha JVM dentro de um script Perl, mas fazer com que o script aguarde a JVM usando a
waitpid
chamada do sistema.Eu sou então informado sempre que a JVM é encerrada e por que ela foi encerrada, e posso tomar as medidas necessárias.
fonte
INT
eTERM
comsun.misc.Signal
, mas não pode controlarQUIT
porque a JVM reserva para depuração, nemKILL
porque o sistema operacional irá encerrar a JVM imediatamente. A tentativa de lidar com qualquer um deles gerará umIllegalArgumentException
.Eu esperaria que a JVM interrompa (
thread.interrupt()
) normalmente todos os threads em execução criados pelo aplicativo, pelo menos para sinaisSIGINT (kill -2)
eSIGTERM (kill -15)
.Dessa forma, o sinal será encaminhado a eles, permitindo um cancelamento de thread e finalização de recursos nas formas padrão .
Mas este não é o caso (pelo menos na minha implementação JVM:
Java(TM) SE Runtime Environment (build 1.8.0_25-b17), Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)
.Como outros usuários comentaram, o uso de ganchos de desligamento parece obrigatório.
Então, como eu lidaria com isso?
Bem, em primeiro lugar, eu não me importo com isso em todos os programas, apenas naqueles em que desejo manter o controle de cancelamentos de usuários e finais inesperados. Por exemplo, imagine que seu programa java é um processo gerenciado por outro. Você pode querer diferenciar se ele foi encerrado normalmente (a
SIGTERM
partir do processo do gerenciador) ou se ocorreu um encerramento (para reiniciar automaticamente o trabalho na inicialização).Como base, eu sempre deixo meus threads de longa duração periodicamente cientes do status de interrupção e lanço um
InterruptedException
se eles foram interrompidos. Isso permite a finalização da execução de forma controlada pelo desenvolvedor (também produzindo o mesmo resultado que as operações de bloqueio padrão). Então, no nível superior da pilha de encadeamentos,InterruptedException
é capturado e a limpeza apropriada é realizada. Esses threads são codificados para saber como responder a uma solicitação de interrupção. Design de alta coesão .Portanto, nesses casos, adiciono um gancho de desligamento, que faz o que acho que a JVM deve fazer por padrão: interromper todos os encadeamentos não daemon criados por meu aplicativo que ainda estão em execução:
Aplicação de teste completa no github: https://github.com/idelvall/kill-test
fonte
Você pode usar
Runtime.getRuntime().addShutdownHook(...)
, mas não pode ter certeza de que será chamado em qualquer caso .fonte
Há uma maneira de reagir a um kill -9: isso é ter um processo separado que monitora o processo que está sendo morto e o limpa depois, se necessário. Isso provavelmente envolveria IPC e seria um pouco trabalhoso, e você ainda pode substituí-lo eliminando os dois processos ao mesmo tempo. Suponho que não valerá a pena na maioria dos casos.
Quem mata um processo com -9 deve, teoricamente, saber o que está fazendo e que isso pode deixar as coisas em um estado inconsistente.
fonte