Posso executar free () ou close () em um manipulador de sinal? [duplicado]
Eu tenho um código parecido com este:
//global variables
void signal_handler() {
//deallocation of global variables
free(foo);
close(foo_2);
exit(0);
}
int main () {
signal(SIGINT, signal_handler);
//irrelevant code
}
Como você pode ver, alterei a CTRL+C
interrupção para executar a signal_handler
função uma vez, em vez de encerrar o processo imediatamente. Eu li em algum lugar que algumas funções como podem ser free
não são assíncronas e NÃO executariam no, signal_handler
mas não tenho certeza sobre isso.
Posso executar funções como free
, close
, exit
ou até mesmo pthread_join
em um manipulador de sinal?
Respostas
Não. Somente as funções listadas em man 7 signal-safety podem ser chamadas com segurança dentro de um manipulador de sinais.
close
está listado e deve ser seguro. free
não é. Por razões pelas quais você teria que olhar seu código-fonte (ele contém bloqueios). exit
não é seguro porque pode chamar manipuladores de limpeza arbitrários. Você tem _exit
que sai abruptamente sem a limpeza.
Você tecnicamente pode compilar um programa que chama tais funções em um manipulador de sinal, nada o impede de fazer isso. No entanto, isso resultará em um comportamento indefinido se a função que você está tentando executar não for segura para sinais assíncronos. Não é como se uma função insegura simplesmente "NÃO fosse executado" como você diz, eles poderiam muito bem, mas ainda seria um comportamento indefinido.
Uma lista de funções de sinal seguro assíncrono está documentada em man 7 signal-safety. A close()
função é segura, enquanto free()
e phtread_join()
não. A exit()
função também não é segura para chamar a partir de um manipulador de sinais, se você deseja sair desse contexto, terá que fazer isso usando _exit().
A única maneira de chamar com segurança uma função que não é segura para sinais assíncronos ao receber um sinal é "lembrar" que você deve chamá-la (por exemplo, definindo uma variável global) e, em seguida, fazer isso após retornar do manipulador de sinal.
A resposta curta é não:
7.1.4 Uso de funções de bibliotecaRascunho Online C 2011
...
4 As funções na biblioteca padrão não são garantidas como reentrantes e podem modificar objetos com duração de armazenamento estático ou thread. 188)
188) Assim, um manipulador de sinal não pode, em geral, chamar funções de biblioteca padrão
Exemplo do mundo real das consequências - trabalhei em um sistema que se comunicava com um banco de dados Access. Houve um manipulador de sinal que tentou gravar uma mensagem de erro no console fprintf
, mas de alguma forma durante o processo de manipulação de sinal stderr
foi mapeado para o arquivo .mdb que armazenava o banco de dados, sobrescrevendo o cabeçalho e arruinando o banco de dados irremediavelmente.
Honestamente, não há muito que você possa fazer em um manipulador de sinais além de definir um sinalizador para ser verificado em outro lugar.
Posso executar free () ou close () em um manipulador de sinal?
Você definitivamente não deveria. Consulte o sinal (7) e o sinal de segurança (7)
Na prática, pode funcionar como você deseja, talvez mais da metade do tempo. IIRC, o compilador GCC está fazendo o que você quer, e geralmente funciona.
Uma abordagem melhor é usar algum write (2) para um pipe (7) (de dentro de seu manipulador de sinal) e de vez em quando verificar esse pipe (em seu programa principal) com poll (2) ou coisas relacionadas.
Ou você pode definir alguns volatile sigatomic_t flag;
(talvez deva ser também _Atomic) em seu manipulador de sinal e verificar esse sinalizador em outro lugar (no programa principal, fora dos manipuladores de sinal).
Qt está explicando isso melhor do que eu poderia fazer em alguns minutos.
No Linux, consulte também signalfd (2) e eventfd (2) .