Sinal
Um sinal é um evento que é gerado para notificar um processo ou thread de que alguma situação importante chegou. Quando um processo ou thread recebe um sinal, o processo ou thread irá parar o que está fazendo e tomar alguma ação. O sinal pode ser útil para a comunicação entre processos.
Sinais Padrão
Os sinais são definidos no arquivo de cabeçalho sinal.h como uma constante macro. O nome do sinal começou com um “SIG” e seguido por uma breve descrição do sinal. Então, cada sinal tem um valor numérico único. Seu programa deve sempre usar o nome dos sinais, não o número dos sinais. O motivo é que o número do sinal pode variar de acordo com o sistema, mas o significado dos nomes será padrão.
A macro NSIG é o número total de sinais definidos. O valor de NSIG é um maior que o número total de sinais definidos (todos os números de sinais são alocados consecutivamente).
A seguir estão os sinais padrão:
Nome do Sinal | Descrição |
SIGHUP | Desligue o processo. O sinal SIGHUP é usado para relatar a desconexão do terminal do usuário, possivelmente porque uma conexão remota foi perdida ou desligada. |
SIGINT | Interromper o processo. Quando o usuário digita o caractere INTR (normalmente Ctrl + C), o sinal SIGINT é enviado. |
SIGQUIT | Saia do processo. Quando o usuário digita o caractere QUIT (normalmente Ctrl + \), o sinal SIGQUIT é enviado. |
SIGILL | Instrução ilegal. Quando é feita uma tentativa de executar uma instrução de lixo ou privilegiada, o sinal SIGILL é gerado. Além disso, SIGILL pode ser gerado quando a pilha estourar ou quando o sistema tiver problemas para executar um manipulador de sinal. |
SIGTRAP | Armadilha de rastreamento. Uma instrução de ponto de interrupção e outra instrução de trap gerará o sinal SIGTRAP. O depurador usa este sinal. |
SIGABRT | Abortar. O sinal SIGABRT é gerado quando a função abort () é chamada. Este sinal indica um erro que é detectado pelo próprio programa e relatado pela chamada de função abort (). |
SIGFPE | Exceção de ponto flutuante. Quando ocorre um erro aritmético fatal, o sinal SIGFPE é gerado. |
SIGUSR1 e SIGUSR2 | Os sinais SIGUSR1 e SIGUSR2 podem ser usados como desejar. É útil escrever um manipulador de sinal para eles no programa que recebe o sinal para uma comunicação simples entre processos. |
Ação Padrão de Sinais
Cada sinal tem uma ação padrão, uma das seguintes:
Prazo: O processo será encerrado.
Testemunho: O processo será encerrado e produzirá um arquivo de despejo central.
Ign: O processo irá ignorar o sinal.
Pare: O processo vai parar.
Cont: O processo continuará sendo interrompido.
A ação padrão pode ser alterada usando a função de manipulador. A ação padrão de alguns sinais não pode ser alterada. SIGKILL e SIGABRT a ação padrão do sinal não pode ser alterada ou ignorada.
Manuseio de Sinal
Se um processo recebe um sinal, o processo tem uma escolha de ação para esse tipo de sinal. O processo pode ignorar o sinal, pode especificar uma função de manipulador ou aceitar a ação padrão para esse tipo de sinal.
- Se a ação especificada para o sinal for ignorada, o sinal será descartado imediatamente.
- O programa pode registrar uma função de manipulador usando funções como sinal ou sigaction. Isso é chamado de manipulador capta o sinal.
- Se o sinal não foi tratado nem ignorado, sua ação padrão ocorre.
Podemos lidar com o sinal usando sinal ou sigação função. Aqui vemos como o mais simples sinal() função é usada para lidar com sinais.
int signal () (int signum, void (* func) (int))O sinal() vai chamar o função função se o processo receber um sinal signum. O sinal() retorna um ponteiro para a função função se for bem sucedido ou retorna um erro para errno e -1 caso contrário.
O função ponteiro pode ter três valores:
- SIG_DFL: É um indicador para a função padrão do sistema SIG_DFL (), declarado em h arquivo de cabeçalho. É usado para tomar a ação padrão do sinal.
- SIG_IGN: É um ponteiro para a função de ignorar do sistema SIG_IGN (),declarado em h arquivo de cabeçalho.
- Ponteiro de função de manipulador definido pelo usuário: O tipo de função do manipulador definido pelo usuário é void (*) (int), significa que o tipo de retorno é nulo e um argumento do tipo int.
Exemplo de manipulador de sinal básico
#incluir#incluir
#incluir
void sig_handler (int signum)
// O tipo de retorno da função do manipulador deve ser nulo
printf ("\ nfunção de tratamento interno \ n");
int main ()
sinal (SIGINT, sig_handler); // Registrar manipulador de sinal
for (int i = 1 ;; i ++) // Loop infinito
printf ("% d: função principal interna \ n", i);
dormir (1); // Atrase por 1 segundo
return 0;
Na captura de tela da saída de Exemplo1.c, podemos ver que na função principal o loop infinito está executando. Quando o usuário digita Ctrl + C, a execução da função principal é interrompida e a função de manipulador do sinal é chamada. Após a conclusão da função de manipulador, a execução da função principal foi retomada. Quando o usuário digita Ctrl + \, o processo é encerrado.
Exemplo de Ignorar Sinais
#incluir#incluir
#incluir
int main ()
sinal (SIGINT, SIG_IGN); // Registra o manipulador de sinal para ignorar o sinal
for (int i = 1 ;; i ++) // Loop infinito
printf ("% d: função principal interna \ n", i);
dormir (1); // Atrase por 1 segundo
return 0;
Aqui, a função do manipulador é registrada para SIG_IGN () função para ignorar a ação do sinal. Então, quando o usuário digitou Ctrl + C, SIGINT o sinal está sendo gerado, mas a ação é ignorada.
Exemplo de manipulador de sinal novamente
#incluir#incluir
#incluir
void sig_handler (int signum)
printf ("\ nFunção de tratamento interno \ n");
sinal (SIGINT, SIG_DFL); // Registre novamente o manipulador de sinal para a ação padrão
int main ()
sinal (SIGINT, sig_handler); // Registrar manipulador de sinal
for (int i = 1 ;; i ++) // Loop infinito
printf ("% d: função principal interna \ n", i);
dormir (1); // Atrase por 1 segundo
return 0;
Na captura de tela da saída de Example3.c, podemos ver que quando o usuário digitou pela primeira vez Ctrl + C, a função de manipulador invocada. Na função de manipulador, o manipulador de sinal se registra novamente para SIG_DFL para ação padrão do sinal. Quando o usuário digita Ctrl + C pela segunda vez, o processo é encerrado, o que é a ação padrão do SIGINT sinal.
Enviando sinais:
Um processo também pode enviar explicitamente sinais para si mesmo ou para outro processo. As funções raise () e kill () podem ser usadas para enviar sinais. Ambas as funções são declaradas no sinal.h arquivo de cabeçalho.
int raise (int signum)A função raise () usada para enviar sinal signum para o processo de chamada (em si). Ele retorna zero se for bem-sucedido e um valor diferente de zero se falhar.
int kill (pid_t pid, int signum)A função kill usada para enviar um sinal signum a um processo ou grupo de processos especificado por pid.
Exemplo de manipulador de sinal SIGUSR1
#incluir#incluir
void sig_handler (int signum)
printf ("Função de manipulador interna \ n");
int main ()
sinal (SIGUSR1, sig_handler); // Registrar manipulador de sinal
printf ("Dentro da função principal \ n");
aumentar (SIGUSR1);
printf ("Função principal interna \ n");
return 0;
Aqui, o processo envia o sinal SIGUSR1 para si mesmo usando a função raise ().
Aumente com Programa de Exemplo de Eliminação
#incluir#incluir
#incluir
void sig_handler (int signum)
printf ("Função de manipulador interna \ n");
int main ()
pid_t pid;
sinal (SIGUSR1, sig_handler); // Registrar manipulador de sinal
printf ("Dentro da função principal \ n");
pid = getpid (); // Processo de identificação por si mesmo
matar (pid, SIGUSR1); // Envie SIGUSR1 para si mesmo
printf ("Função principal interna \ n");
return 0;
Aqui, o processo envia SIGUSR1 sinalizar para si mesmo usando mate() função. getpid () é usado para obter o próprio ID do processo.
No próximo exemplo, veremos como os processos pai e filho se comunicam (comunicação entre processos) usando mate() e função de sinal.
Comunicação entre pais e filhos com sinais
#incluir#incluir
#incluir
#incluir
void sig_handler_parent (int signum)
printf ("Pai: recebeu um sinal de resposta da criança \ n");
void sig_handler_child (int signum)
printf ("Criança: recebeu um sinal do pai \ n");
dormir (1);
matar (getppid (), SIGUSR1);
int main ()
pid_t pid;
if ((pid = fork ())<0)
printf ("Bifurcação falhou \ n");
saída (1);
/ * Processo filho * /
else if (pid == 0)
sinal (SIGUSR1, sig_handler_child); // Registrar manipulador de sinal
printf ("Criança: aguardando sinal \ n");
pausa();
/ * Processo Pai * /
senão
sinal (SIGUSR1, sig_handler_parent); // Registrar manipulador de sinal
dormir (1);
printf ("Pai: enviando sinal para filho \ n");
matar (pid, SIGUSR1);
printf ("Pai: aguardando resposta \ n");
pausa();
return 0;
Aqui, garfo() função cria o processo filho e retorna zero para o processo filho e o ID do processo filho para o processo pai. Então, pid foi verificado para decidir o processo pai e filho. No processo pai, ele é adormecido por 1 segundo para que o processo filho possa registrar a função de manipulador de sinal e esperar pelo sinal do pai. Após 1 segundo processo pai enviar SIGUSR1 sinalizar para o processo filho e aguardar o sinal de resposta do filho. No processo filho, primeiro ele está esperando pelo sinal do pai e quando o sinal é recebido, a função do manipulador é chamada. A partir da função de manipulador, o processo filho envia outro SIGUSR1 sinalizar para os pais. Aqui getppid () função é usada para obter o ID do processo pai.
Conclusão
Sinal no Linux é um grande tópico. Neste artigo, vimos como lidar com o sinal desde o básico e também obter um conhecimento de como o sinal é gerado, como um processo pode enviar sinal para si mesmo e para outro processo, como o sinal pode ser usado para comunicação entre processos.