Use a sigaction()
menos que você tenha razões muito convincentes para não fazer isso.
A signal()
interface tem antiguidade (e, portanto, disponibilidade) a seu favor, e é definida no padrão C. No entanto, ele tem várias características indesejáveis que sigaction()
evitam - a menos que você use as bandeiras adicionadas explicitamente sigaction()
para permitir que ele simule fielmente o signal()
comportamento antigo .
- A
signal()
função não (necessariamente) impede que outros sinais cheguem enquanto o manipulador atual está em execução; sigaction()
pode bloquear outros sinais até que o manipulador atual retorne.
- A
signal()
função (geralmente) redefine a ação do sinal de volta para SIG_DFL
(padrão) para quase todos os sinais. Isso significa que o signal()
manipulador deve se reinstalar como sua primeira ação. Ele também abre uma janela de vulnerabilidade entre o momento em que o sinal é detectado e o manipulador é reinstalado, durante o qual, se uma segunda instância do sinal chegar, o comportamento padrão (geralmente termina, às vezes com preconceito - também conhecido como core dump).
- O comportamento exato de
signal()
varia entre sistemas - e os padrões permitem essas variações.
Geralmente, essas são boas razões para usar em sigaction()
vez de signal()
. No entanto, a interface do sigaction()
é inegavelmente mais complicada.
Qualquer que seja a dos dois que você usa, não ser tentado pelas interfaces de sinal alternativos, como
sighold()
,
sigignore()
,
sigpause()
e
sigrelse()
. Eles são nominalmente alternativas sigaction()
, mas são pouco padronizados e estão presentes no POSIX para compatibilidade com versões anteriores, e não para uso sério. Observe que o padrão POSIX diz que seu comportamento em programas multiencadeados é indefinido.
Programas e sinais multithread são outra história complicada. AFAIK, ambos signal()
e sigaction()
estão OK em aplicativos multithread.
Cornstalks observa :
A página de manual do Linux para signal()
diz:
Os efeitos de signal()
um processo multiencadeado não são especificados.
Portanto, acho que sigaction()
é o único que pode ser usado com segurança em um processo multiencadeado.
Isso é interessante. A página de manual do Linux é mais restritiva que o POSIX neste caso. O POSIX especifica para signal()
:
Se o processo for multithread, ou se o processo for single-thread, e um manipulador de sinal for executado, exceto como resultado de:
- O chamado processo
abort()
, raise()
, kill()
, pthread_kill()
, ou sigqueue()
para gerar um sinal de que não está bloqueado
- Um sinal pendente sendo desbloqueado e entregue antes da chamada que o desbloqueou retornar
o comportamento é indefinido se o manipulador de sinal se referir a qualquer objeto que não seja errno
com duração de armazenamento estático, além de atribuir um valor a um objeto declarado como volatile sig_atomic_t
, ou se o manipulador de sinal chamar qualquer função definida neste padrão que não seja uma das funções listadas em Conceitos de sinal .
Portanto, o POSIX especifica claramente o comportamento de signal()
um aplicativo multiencadeado.
No entanto, sigaction()
deve ser preferido em praticamente todas as circunstâncias - e o código multithread portátil deve sigaction()
ser usado, a menos que haja uma razão avassaladora para que não possa (como "usar apenas funções definidas pelo Padrão C" - e sim, o código C11 pode ser multi rosqueado). Que é basicamente o que o parágrafo de abertura desta resposta também diz.
signal
é realmente o comportamento do Unix System V. O POSIX permite esse comportamento ou o BSD muito mais sensato, mas como você não tem certeza de qual deles obterá, ainda é melhor usá-losigaction
.SA_RESETHAND
tambémSA_NODEFER
.sigaction()
, você é essencialmente obrigado a usar a especificação C padrãosignal()
. No entanto, isso oferece um conjunto de opções extremamente empobrecido para o que você pode fazer. Você pode: modificar (escopo do arquivo) variáveis do tipovolatile sig_atomic_t
; chame uma das funções de 'saída rápida' (_Exit()
,quick_exit()
) ouabort()
; chamarsignal()
com o número do sinal atual como argumento do sinal; Retorna. E é isso. Não há garantia de que qualquer outra coisa seja portátil. Isso é tão rigoroso que a maioria das pessoas ignora essas regras - mas o código resultante é desonesto.sigaction()
demonstração do próprio GCC: gnu.org/software/libc/manual/html_node/… ; e excelentesignal()
demonstração do próprio GCC: gnu.org/software/libc/manual/html_node/… . Observe que, nasignal
demonstração, eles evitam alterar o manipulador de ignore (SIG_IGN
) se for para isso que ele foi intencionalmente definido anteriormente.Para mim, essa linha abaixo foi suficiente para decidir:
http://pubs.opengroup.org/onlinepubs/009695399/functions/signal.html#tag_03_690_07
Esteja você começando do zero ou modificando um programa antigo, a sigação deve ser a opção certa.
fonte
São interfaces diferentes para os recursos de sinal do SO. Deve-se preferir usar sigaction para sinalizar, se possível, pois o sinal () possui um comportamento definido pela implementação (geralmente propenso a corridas) e se comporta de maneira diferente no Windows, OS X, Linux e outros sistemas UNIX.
Consulte esta nota de segurança para obter detalhes.
fonte
sinal () é padrão C, sigaction () não é.
Se você pode usar qualquer um (ou seja, você está em um sistema POSIX), use sigaction (); não é especificado se signal () redefine o manipulador, o que significa que, para ser portátil, você precisa chamar o sinal () novamente dentro do manipulador. O pior é que há uma corrida: se você receber dois sinais em rápida sucessão e o segundo for entregue antes de reinstalar o manipulador, você terá a ação padrão, que provavelmente matará seu processo. sigaction () , por outro lado, é garantido para usar semântica de sinal "confiável". Você não precisa reinstalar o manipulador, porque ele nunca será redefinido. Com o SA_RESTART, você também pode receber algumas chamadas do sistema para reiniciar automaticamente (para que você não precise verificar manualmente o EINTR). sigaction () tem mais opções e é confiável, portanto, seu uso é incentivado.
Psst ... não conte a ninguém que eu te disse isso, mas o POSIX atualmente possui uma função bsd_signal () que age como sinal (), mas fornece semântica BSD, o que significa que é confiável. Seu principal uso é para portar aplicativos antigos que assumiam sinais confiáveis, e o POSIX não recomenda usá-lo.
fonte
bsd_signal()
- algumas implementações do POSIX podem ter a função, mas o próprio POSIX não contém essa função (consulte POSIX ).Em resumo:
sigaction()
é bom e bem definido, mas é uma função do Linux e, portanto, funciona apenas no Linux.signal()
é ruim e mal definido, mas é uma função padrão C e, portanto, funciona em qualquer coisa.O que as páginas de manual do Linux têm a dizer sobre isso?
man 2 signal
(veja online aqui ) declara:Em outras palavras: não use
signal()
. Use emsigaction()
vez disso!O que o GCC pensa?
Fonte: https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handling
Então, se o Linux e o GCC dizem para não usar
signal()
, mas usarsigaction()
, isso levanta a questão: como diabos usamos essasigaction()
coisa confusa ?Exemplos de uso:
Leia o EXCELENTE
signal()
exemplo do GCC aqui: https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-HandlingE o EXCELENTE
sigaction()
exemplo aqui: https://www.gnu.org/software/libc/manual/html_node/Sigaction-Function-Example.htmlDepois de ler essas páginas, criei a seguinte técnica para
sigaction()
:1.
sigaction()
, pois é o caminho certo para conectar um manipulador de sinal, conforme descrito acima:2. E
signal()
, apesar de não ser uma boa maneira de conectar um manipulador de sinal, como descrito acima, ainda é bom saber como usá-lo.Aqui está o código de demonstração do GCC copiado e colado, pois é tão bom quanto possível:
Os principais links para estar ciente de:
signal()
exemplo oficial de uso do GCC : https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handlingsigaction()
Exemplo oficial de uso do GCC : https://www.gnu.org/software/libc/manual/html_node/Sigaction-Function-Example.htmlsigemptyset()
esigfillset()
; Ainda não entendi exatamente, mas sei que são importantes: https://www.gnu.org/software/libc/manual/html_node/Signal-Sets.htmlVeja também:
fonte
Na
signal(3)
página do manual:Ambos invocam o mesmo recurso subjacente. Presumivelmente, você não deve manipular a resposta de um único sinal com ambos, mas misturá-los não deve fazer com que nada quebre ...
fonte
Eu também sugeriria usar sigaction () sobre o sinal () e gostaria de adicionar mais um ponto. sigaction () oferece mais opções, como pid do processo que morreu (possível usando a estrutura siginfo_t).
fonte
Eu usaria o sinal (), pois é mais portátil, pelo menos em teoria. Vou votar em qualquer comentarista que possa criar um sistema moderno que não tenha uma camada de compatibilidade POSIX e suporte a sinal ().
Citando a partir da documentação GLIBC :
fonte
Do sinal da página de manual (7)
E eu diria que esse "problema" existe para o sinal (2) e sigaction (2) . Portanto, tenha cuidado com sinais e pinos.
... e o sinal (2) parece chamar sigaction (2) abaixo no Linux com glibc.
fonte