minhas informações de contato
Correspondência[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Sinal (sinal) é uma interrupção de software. É um método de transmissão de mensagens entre processos. É usado para notificar o processo de que ocorreu um evento, mas não pode transmitir nenhum dado ao processo.
Existem muitos motivos pelos quais os sinais são gerados no Shell, que você pode usar.kill
ekillall
Comando para enviar sinal:
kill -信号的类型 进程编号
killall -信号的类型 进程名
nome do sinal | valor do sinal | Ação de processamento padrão | Motivo da sinalização |
---|---|---|---|
SUSPIRO | 1 | A | O terminal trava ou o processo de controle termina |
ASSINATURA | 2 | A | Interrupção de teclado Ctrl+c |
SIGQUIT | 3 | C | A tecla Escape do teclado é pressionada |
SIGILO | 4 | C | Instrução ilegal |
ARMADILHA SIG | 5 | C | instruções de ponto de interrupção |
SIGABRTE | 6 | C | Sinal de aborto emitido por abort(3) |
SIGBUS | 7 | C | erro de ônibus |
SIGFPE | 8 | C | exceção de ponto flutuante |
SIGMATAR | 9 | A | kill -9 mata o processo, este sinal não pode ser capturado e ignorado |
SIGUSR1 | 10 | A | Sinal definido pelo usuário 1 |
SIGSEGV | 11 | C | Referência de memória inválida (matriz fora dos limites, operação de ponteiro nulo) |
SIGUSR2 | 12 | A | Sinal definido pelo usuário 2 |
Tubo Sigpipe | 13 | A | Gravar dados em um pipe sem um processo de leitura |
SIGALRM | 14 | A | Sinal de despertador, sinal enviado pela função alarm() |
SIGTERM | 15 | A | Sinal de terminação, o sinal enviado por padrão |
SIGSTKFLT | 16 | A | erro de pilha |
ASSINATURA | 17 | B | Emitido quando o processo filho termina |
SIGCONT | 18 | E | Retomar um processo interrompido |
SIGSTOP | 19 | E | Parar processo |
SIGTSTP | 20 | E | Terminal pressione a tecla parar |
SIGTTIN | 21 | E | Solicitações de processo em segundo plano para ler o terminal |
SIGTOU | 22 | E | O processo em segundo plano solicita gravação no terminal |
SIGURG | 23 | B | Detecção de condição de emergência (soquetes) |
CPU SIGX | 24 | C | Limite de tempo da CPU excedido |
SIGXFSZ | 25 | C | Limite de tamanho de arquivo excedido |
SIGVTALRM | 26 | A | sinal de relógio virtual |
PROFISSÃO SIG | 27 | A | Analise os sinais do relógio |
Guincho de Sinalização | 28 | B | Mudanças no tamanho da janela |
Pesquisa SigPoll | 29 | B | Pesquisa (Sys V) |
SIGPWR | 30 | A | falha de eletricidade |
SIGSYS | 31 | C | Chamada de sistema ilegal |
A ação padrão de A é encerrar o processo.
A ação padrão de B é ignorar este sinal.
A ação padrão de C é encerrar o processo e fazer um dump da imagem do kernel.
A ação padrão de D é interromper o processo e o programa que entra no estado parado pode continuar a ser executado.
Existem três maneiras de os processos lidarem com sinais:
signal()
As funções podem definir como o programa trata os sinais.
Declaração de função:
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
Descrição do parâmetro:
sig
:Especifique o sinal a ser capturado.func
: Ponteiro para função de processamento de sinal. A função de processamento precisa receber um parâmetro inteiro, que é o número do sinal capturado.SIG_DFL
A macro :SIG_DFL representa o método de processamento de sinal padrão.usarSIG_DFL
comosignal
O segundo parâmetro da função indica que o método de processamento padrão do sistema é usado para o sinal.SIG_IGN
A macro :SIG_IGN significa ignorar o sinal.usarSIG_IGN
comosignal
O segundo parâmetro da função indica que quando o processo receber o sinal, ele irá ignorá-lo e não realizará nenhum processamento. Isso pode evitar que processos sejam encerrados ou interrompidos inesperadamente em determinadas circunstâncias.SIG_ERR
:SIG_ERR
Macros são usadas para indicar erros.não é tãosignal
O segundo parâmetro da função é usado comosignal
O valor de retorno da função indica que a chamada falhou.sesignal
Se a chamada para a função falhar, ela retornaráSIG_ERR
.Isso normalmente é usado para detectar e processarsignal
Erro na chamada de função.O programa de serviço é executado em segundo plano. Se você quiser interrompê-lo, matá-lo não é uma boa ideia, porque quando o processo é encerrado, ele morre repentinamente e nenhum trabalho posterior é organizado.
Se você enviar um sinal para o programa de serviço, após receber o sinal, o programa de serviço chamará uma função e escreverá o código posterior na função, e o programa poderá sair de maneira planejada.
Enviar um sinal 0 ao programa de serviço pode detectar se o programa está ativo.
O sistema operacional Linux fornece kill
ekillall
O comando envia um sinal para o programa No programa, você pode usar.kill()
As funções da biblioteca enviam sinais para outros processos.
Declaração de função:
int kill(pid_t pid, int sig);
kill()
A função recebe os parâmetrossig
O sinal especificado é passado para o parâmetropid
processo especificado.
parâmetro pid
Existem várias situações:
pid > 0
Passe o sinal para o processo comopid
processo.pid = 0
Passe o sinal para todos os processos no mesmo grupo de processos do processo atual. Geralmente é usado pelo processo pai para enviar sinais ao processo filho.pid < -1
Passe o sinal para o ID do grupo de processos de|pid|
de todos os processos.pid = -1
Passa o sinal para todos os processos que têm permissão para enviar o sinal, mas não para o processo que enviou o sinal.Existem 8 maneiras de encerrar um processo, sendo 5 delas encerrações normais, são elas:
main()
Para funçõesreturn
retornar;exit()
função;_exit()
ou_Exit()
função;return
retornar;pthread_exit()
retornar;Existem três maneiras de encerrar de forma anormal, são elas:
abort()
abortar função;existir main()
Na função,return
O valor retornado é o status de encerramento, caso contrárioreturn
declaração ou chamadaexit()
, então o status de encerramento do processo é 0.
No shell, visualize o status do encerramento do processo:
echo $?
3 funções para encerrar o processo normalmente (exit()
e_Exit()
é especificado pela ISO C,_exit()
é especificado pelo POSIX):
void exit(int status);
void _exit(int status);
void _Exit(int status);
status
O status de encerramento do processo.
return
Indica que quando a função retornar, o destruidor do objeto local será chamado.main()
em funçãoreturn
O destruidor do objeto global também é chamado.exit()
Indica para encerrar o processo, o destruidor do objeto local não será chamado, apenas o destruidor do objeto global será chamado._exit()
e_Exit()
Saia diretamente e nenhum trabalho de limpeza será realizado.O processo está disponível atexit()
O registro de função encerra funções (até 32), essas funções serãoexit()
Chamado automaticamente.
int atexit(void (*function)(void));
exit()
A ordem em que as funções de encerramento são chamadas é invertida a partir do momento do registro.
system()
A função fornece um método simples para executar o programa, passando o programa e os parâmetros que precisam ser executados como uma string.system()
Apenas funcione.
Declaração de função:
int system(const char * string);
system()
O valor de retorno da função é mais problemático.
system()
A função retorna diferente de zero;system()
A função retorna 0;system()
A função retorna diferente de zero.exec
As famílias de funções fornecem outra maneira de chamar programas (binários ou scripts de shell) dentro de um processo.
exec
A família de funções é declarada da seguinte forma:
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
Perceber:
errno
meio.exec
Depois disso, o programa chamado substituirá o programa chamador, ou seja,exec
Nenhum código após a função será executado.execl()
eexecv()
, outros raramente são usados.Todos os processos em todo o sistema Linux estão em uma estrutura em árvore.
usarpstree
Você pode visualizar a árvore do processo com o comando:
pstree -p 进程编号
Cada processo possui um ID de processo exclusivo representado por um número inteiro não negativo. Embora exclusivos, os IDs de processo podem ser reutilizados. Quando um processo termina, seu ID de processo torna-se candidato à reutilização. O Linux usa um algoritmo de reutilização atrasada para que o ID de um processo recém-criado seja diferente do ID usado pelo processo encerrado recentemente. Isso evita que novos processos sejam confundidos com um processo encerrado usando o mesmo ID.
Função para obter o ID do processo:
pid_t getpid(void); // 获取当前进程的ID。
pid_t getppid(void); // 获取父进程的ID。
Um processo existente pode chamarfork()
A função cria um novo processo.
Declaração de função:
pid_t fork(void);
Depende defork()
O novo processo criado é chamado de processo filho.
fork()
A função é chamada uma vez, mas retorna duas vezes. A diferença entre os dois retornos é que o valor de retorno do processo filho é 0, enquanto o valor de retorno do processo pai é o ID do processo filho recém-criado.
O processo filho e o processo pai continuam em execuçãofork()
O código depois disso, O processo filho é uma cópia do processo pai. O processo filho possui uma cópia do espaço de dados, heap e pilha do processo pai (nota: o processo filho possui uma cópia, não compartilhada com o processo pai).
fork()
Depois disso, a ordem de execução dos processos pai e filho é indefinida.
fork()
, deixe o processo filho lidar com essas solicitações, enquanto o processo pai continua aguardando a próxima solicitação de conexão.fork()
Chamado imediatamente após o retornoexec
。fork()
Um recurso é que os descritores de arquivo abertos no processo pai serão copiados para o processo filho, e o processo pai e o processo filho compartilham o mesmo deslocamento de arquivo.
Se um processo pai e um processo filho gravarem em um arquivo apontado pelo mesmo descritor sem qualquer forma de sincronização, suas saídas poderão ser misturadas entre si.
Neste ponto você pode ver que existem apenas 100.000 linhas de dados.
Neste momento, deve haver 200.000 linhas de dados. Uma linha a menos pode ser porque a operação de gravação do arquivo não é atômica. Na ausência de um mecanismo de sincronização, dois processos podem tentar gravar partes diferentes do arquivo ao mesmo tempo. fazendo com que a gravação falhe.
vfork()
Chamadas de função e valores de retorno são iguais afork()
O mesmo, mas sua semântica é diferente.
vfork()
A função é usada para criar um novo processo cujo objetivo éexec
Um novo programa que não copia o espaço de endereço do processo pai porque o processo filho chama imediatamenteexec
, portanto, o espaço de endereço do processo pai não será usado. Se o processo filho usar o espaço de endereço do processo pai, poderão ocorrer resultados desconhecidos.
vfork()
efork()
Outra diferença é:vfork()
Certifique-se de que o processo filho seja executado primeiro e chame-o no processo filhoexec
ouexit
Então o processo pai retoma a operação.
No sistema operacional, um processo zumbi refere-se a um processo filho que foi encerrado, mas seu processo pai ainda não leu seu status de saída. Embora o processo zumbi não esteja mais em execução, ele ainda ocupa uma entrada na tabela de processos para que o kernel possa salvar as informações de status de saída do processo (como ID do processo, status de saída, etc.) até que o processo pai leia essas informações.
Se o processo pai sair antes do processo filho, o processo filho será hospedado pelo processo 1 (essa também é uma forma de permitir que o processo seja executado em segundo plano).
Se o processo filho sair antes do processo pai e o processo pai não processar as informações de saída do processo filho, o processo filho se tornará um processo zumbi.
O kernel retém uma estrutura de dados para cada processo filho, incluindo número do processo, status de encerramento, tempo de CPU usado, etc. Se o processo pai processar as informações de saída do processo filho, o kernel liberará essa estrutura de dados. Se o processo pai não processar as informações de saída do processo filho, o kernel não liberará essa estrutura de dados e o número do processo filho estará sempre ocupado. Os números de processos disponíveis no sistema são limitados. Se um grande número de processos zumbis for gerado, o sistema não será capaz de gerar novos processos porque não há números de processos disponíveis.
signal(SIGCHLD, SIG_IGN)
Notifique o kernel que ele não está interessado na saída do processo filho, e sua estrutura de dados será liberada imediatamente após a saída do processo filho.wait()
/waitpid()
função: O processo pai espera que o processo filho termine chamando essas funções e obtém seu status de saída, liberando assim os recursos ocupados pelo processo filho.pid_t wait(int *stat_loc);
pid_t waitpid(pid_t pid, int *stat_loc, int options);
pid_t wait3(int *status, int options, struct rusage *rusage);
pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage);
O valor de retorno é o número do processo filho.
stat_loc
A informação sobre o encerramento do processo filho é:
a) Se encerrado normalmente, a macro WIFEXITED(stat_loc)
Retornar verdadeiro, macroWEXITSTATUS(stat_loc)
O status de rescisão pode ser obtido;
b) Se terminar de forma anormal, a macro WTERMSIG(stat_loc)
Obtém o sinal para encerrar o processo.
Se o processo pai estiver ocupado, você poderá capturar SIGCHLD
Sinal, chamado na função de processamento de sinalwait()
/waitpid()
。
[Enviar sinais entre processos](##1.5 Enviar sinais)
Em um programa de serviço multiprocesso, se o subprocesso receber um sinal de saída, o subprocesso sairá sozinho.
Se o processo pai receber um sinal de saída, ele deverá enviar sinais de saída para todos os processos filhos e então sair.
Multi-threads compartilham o espaço de endereço de um processo,Se vários threads precisarem acessar a mesma memória, basta usar variáveis globais.。
Em múltiplos processos, o espaço de endereço de cada processo é independente e não compartilhado.Se vários processos precisarem acessar a mesma memória, variáveis globais não poderão ser usadas, apenas memória compartilhada poderá ser usada.。
A memória compartilhada permite que vários processos (nenhuma relação sanguínea entre processos é necessária) acessem o mesmo espaço de memória. É a maneira mais eficaz de compartilhar e transferir dados entre vários processos. Os processos podem conectar a memória compartilhada ao seu próprio espaço de endereço. Se um processo modificar os dados na memória compartilhada, os dados lidos por outros processos também serão alterados.
A memória compartilhada não fornece um mecanismo de bloqueio, ou seja, quando um processo lê/grava na memória compartilhada, ele não impede que outros processos a leiam/escrevam.Se você deseja bloquear a leitura/gravação da memória compartilhada, você pode usar um semáforo . O Linux fornece um conjunto de funções para operar memória compartilhada.
Esta função é usada para criar/adquirir memória compartilhada.
int shmget(key_t key, size_t size, int shmflg);
typedef unsigned int key_t
), geralmente em hexadecimal, por exemplo 0x5005
, as chaves das diferentes memórias compartilhadas não podem ser iguais.0666|IPC_CREAT
Indica que se a memória compartilhada não existir, crie-a.usar ipcs -m
Você pode visualizar a memória compartilhada do sistema, incluindo: chave, ID de memória compartilhada (shmid), proprietário, permissões (perms) e tamanho (bytes).
usar ipcrm -m 共享内存id
A memória compartilhada pode ser excluída manualmente da seguinte forma:
Nota: Os contêineres não podem ser usados para tipos de dados em memória compartilhada, apenas tipos de dados básicos podem ser usados.
Esta função é usada para conectar a memória compartilhada ao espaço de endereço do processo atual.
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmget()
O identificador de memória compartilhada retornado pela função.Retorna o endereço inicial da memória compartilhada quando a chamada é bem-sucedida e retorna quando falha. (void *)-1
。
Esta função é usada para separar a memória compartilhada do processo atual, o que equivale a shmat()
A operação inversa de uma função.
int shmdt(const void *shmaddr);
shmat()
O endereço retornado pela função.Retorna 0 se a chamada for bem-sucedida e -1 se falhar.
Esta função é usada para operar a memória compartilhada. A operação mais comumente usada é excluir a memória compartilhada.
int shmctl(int shmid, int command, struct shmid_ds *buf);
shmget()
O ID da memória compartilhada retornado pela função.IPC_RMID
。Retorna 0 se a chamada for bem-sucedida e -1 se falhar.
Observe, use root
A memória compartilhada criada não pode ser excluída por usuários comuns, independentemente das permissões criadas.
Retorna 0 se a chamada for bem-sucedida e -1 se falhar.
Esta função é usada para operar a memória compartilhada. A operação mais comumente usada é excluir a memória compartilhada.
int shmctl(int shmid, int command, struct shmid_ds *buf);
shmget()
O ID da memória compartilhada retornado pela função.IPC_RMID
。Retorna 0 se a chamada for bem-sucedida e -1 se falhar.
Observe, use root
A memória compartilhada criada não pode ser excluída por usuários comuns, independentemente das permissões criadas.
[As imagens do link externo estão sendo transferidas...(img-v6qW3XRA-1720711279572)]
[As imagens do link externo estão sendo transferidas...(img-CG0tGAne-1720711279572)]