le mie informazioni di contatto
Posta[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Il segnale (segnale) è un'interruzione del software. È un metodo per trasmettere messaggi tra processi. Viene utilizzato per notificare al processo che si è verificato un evento, ma non può passare alcun dato al processo.
Ci sono molti motivi per cui i segnali vengono generati nella Shell, è possibile utilizzarlikill
Ekillall
Comando per inviare il segnale:
kill -信号的类型 进程编号
killall -信号的类型 进程名
nome del segnale | valore del segnale | Azione di elaborazione predefinita | Motivo della segnalazione |
---|---|---|---|
ISCRIVITI | 1 | UN | Il terminale si blocca o il processo di controllo termina |
SIGINT | 2 | UN | Interruzione da tastiera Ctrl+c |
SIGQUIT | 3 | C | Viene premuto il tasto Esc della tastiera |
Sigillo | 4 | C | Istruzione illegale |
Sigtrap | 5 | C | istruzioni sui punti di interruzione |
Sigabrt | 6 | C | Segnale di interruzione emesso da abort(3) |
SIGBUS | 7 | C | errore dell'autobus |
SIGFPE | 8 | C | eccezione in virgola mobile |
SIGILLO | 9 | UN | kill -9 uccide il processo, questo segnale non può essere catturato e ignorato |
SIGUSR1 | 10 | UN | Segnale definito dall'utente 1 |
SIGSEGV | 11 | C | Riferimento di memoria non valido (array fuori dai limiti, operazione con puntatore nullo) |
SIGUSR2 | 12 | UN | Segnale definito dall'utente 2 |
TUBO PER SIGILLO | 13 | UN | Scrivere i dati in una pipe senza un processo di lettura |
Sigillo | 14 | UN | Segnale sveglia, segnale inviato dalla funzione alert() |
SIGTERM | 15 | UN | Segnale di terminazione, il segnale inviato per impostazione predefinita |
Sig.ra | 16 | UN | errore di pila |
SIGILLATO | 17 | B | Emesso al termine del processo figlio |
SIGCONT | 18 | D | Riprendere un processo interrotto |
SIGSTOP | 19 | D | Interrompere il processo |
SigtTP | 20 | D | Il terminale preme il tasto stop |
Sigillo | 21 | D | Il processo in background richiede di leggere il terminale |
SIGTTOU | 22 | D | Il processo in background richiede di scrivere sul terminale |
Sigillo | 23 | B | Rilevamento delle condizioni di emergenza (prese) |
SIGXCPU | 24 | C | Limite di tempo della CPU superato |
SigXFSZ | 25 | C | Limite dimensione file superato |
SIGVTALRM | 26 | UN | segnale dell'orologio virtuale |
Sigprof | 27 | UN | Analizzare i segnali di clock |
VERRICELLO SIGILLANTE | 28 | B | La dimensione della finestra cambia |
Sondaggio Sigma | 29 | B | Polling (Sistema V) |
Sigmawr | 30 | UN | mancanza di energia elettrica |
SIGSISTEMI | 31 | C | Chiamata di sistema illegale |
L'azione predefinita di A è terminare il processo.
L'azione predefinita di B è ignorare questo segnale.
L'azione predefinita di C è terminare il processo ed eseguire un dump dell'immagine del kernel.
L'azione predefinita di D è arrestare il processo e il programma che entra nello stato interrotto può continuare l'esecuzione.
I processi possono gestire i segnali in tre modi:
signal()
Le funzioni possono impostare il modo in cui il programma gestisce i segnali.
Dichiarazione di funzione:
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
Descrizione dei parametri:
sig
:Specificare il segnale da catturare.func
: Puntatore alla funzione di elaborazione del segnale. La funzione di elaborazione deve ricevere un parametro intero, che è il numero del segnale catturato.SIG_DFL
La macro :SIG_DFL rappresenta il metodo di elaborazione del segnale predefinito.utilizzoSIG_DFL
COMEsignal
Il secondo parametro della funzione indica che per il segnale viene utilizzato il metodo di elaborazione predefinito del sistema.SIG_IGN
La macro :SIG_IGN significa ignorare il segnale.utilizzoSIG_IGN
COMEsignal
Il secondo parametro della funzione indica che quando il processo riceve il segnale, lo ignorerà e non eseguirà alcuna elaborazione. Ciò può impedire che i processi vengano terminati o interrotti inaspettatamente in determinate circostanze.SIG_ERR
:SIG_ERR
Le macro vengono utilizzate per indicare gli errori.non è cosìsignal
Il secondo parametro della funzione viene invece utilizzato comesignal
Il valore restituito dalla funzione indica che la chiamata non è riuscita.Sesignal
Se la chiamata alla funzione fallisce, verrà restituitaSIG_ERR
.Questo viene in genere utilizzato per rilevare ed elaboraresignal
Errore nella chiamata di funzione.Il programma di servizio viene eseguito in background. Se vuoi fermarlo, ucciderlo non è una buona idea, perché quando il processo viene interrotto, muore improvvisamente e non viene organizzato alcun lavoro successivo.
Se si invia un segnale al programma di servizio, dopo aver ricevuto il segnale, il programma di servizio chiama una funzione e scrive il codice successivo nella funzione, e il programma può uscire in modo pianificato.
L'invio di un segnale pari a 0 al programma di servizio può rilevare se il programma è attivo.
Il sistema operativo Linux fornisce kill
Ekillall
Il comando invia un segnale al programma Nel programma è possibile utilizzarekill()
Le funzioni di libreria inviano segnali ad altri processi.
Dichiarazione di funzione:
int kill(pid_t pid, int sig);
kill()
La funzione accetta i parametrisig
Il segnale specificato viene passato al parametropid
processo specificato.
parametro pid
Ci sono diverse situazioni:
pid > 0
Passa il segnale al processo comepid
processi.pid = 0
Passa il segnale a tutti i processi nello stesso gruppo di processi del processo corrente Viene spesso utilizzato dal processo genitore per inviare segnali al processo figlio. Si noti che questo comportamento dipende dall'implementazione del sistema.pid < -1
Passa il segnale all'ID del gruppo di processi di|pid|
di tutti i processi.pid = -1
Passa il segnale a tutti i processi che dispongono dell'autorizzazione per inviare il segnale, ma non al processo che ha inviato il segnale.Esistono 8 modi per terminare un processo, 5 dei quali sono terminazioni normali, ovvero:
main()
Per le funzionireturn
ritorno;exit()
funzione;_exit()
O_Exit()
funzione;return
ritorno;pthread_exit()
ritorno;Esistono tre modi per terminare in modo anomalo:
abort()
interruzione della funzione;esistere main()
Nella funzione,return
In caso contrario, il valore restituito è lo stato di terminazionereturn
dichiarazione o chiamataexit()
, allora lo stato di terminazione del processo è 0.
Nella shell, visualizza lo stato di terminazione del processo:
echo $?
3 funzioni per terminare il processo normalmente (exit()
E_Exit()
è specificato dalla ISO C,_exit()
è specificato da POSIX):
void exit(int status);
void _exit(int status);
void _Exit(int status);
status
Lo stato di conclusione del processo.
return
Indica che al termine della funzione verrà chiamato il distruttore dell'oggetto locale.main()
in funzionereturn
Viene chiamato anche il distruttore dell'oggetto globale.exit()
Indica di terminare il processo, non verrà chiamato il distruttore dell'oggetto locale, verrà chiamato solo il distruttore dell'oggetto globale._exit()
E_Exit()
Esci direttamente e non verrà eseguita alcuna operazione di pulizia.Il processo è disponibile atexit()
La registrazione delle funzioni termina le funzioni (fino a 32), queste funzioni sarannoexit()
Chiamato automaticamente.
int atexit(void (*function)(void));
exit()
L'ordine in cui vengono richiamate le funzioni di terminazione è invertito dal momento della registrazione.
system()
La funzione fornisce un metodo semplice per eseguire il programma, passando il programma e i parametri che devono essere eseguiti come una stringa.system()
Funziona e basta.
Dichiarazione di funzione:
int system(const char * string);
system()
Il valore restituito dalla funzione è più problematico.
system()
La funzione restituisce un valore diverso da zero;system()
La funzione restituisce 0;system()
La funzione restituisce un valore diverso da zero.exec
Le famiglie di funzioni forniscono un altro modo per chiamare programmi (binari o script di shell) all'interno di un processo.
exec
La famiglia di funzioni è dichiarata come segue:
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[]);
Avviso:
errno
mezzo.exec
Successivamente, il programma chiamato sostituirà il programma chiamante, ovveroexec
Nessun codice dopo la funzione verrà eseguito.execl()
Eexecv()
, altri sono usati raramente.Tutti i processi nell'intero sistema Linux sono disposti in una struttura ad albero.
utilizzopstree
È possibile visualizzare l'albero del processo con il comando:
pstree -p 进程编号
Ogni processo ha un ID processo univoco rappresentato da un numero intero non negativo. Sebbene univoci, gli ID processo possono essere riutilizzati. Quando un processo termina, il suo ID processo diventa un candidato per il riutilizzo. Linux utilizza un algoritmo di riutilizzo ritardato in modo che l'ID di un processo appena creato sia diverso dall'ID utilizzato dal processo recentemente terminato. Ciò impedisce che i nuovi processi vengano confusi con un processo terminato che utilizza lo stesso ID.
Funzione per ottenere l'ID del processo:
pid_t getpid(void); // 获取当前进程的ID。
pid_t getppid(void); // 获取父进程的ID。
Un processo esistente può chiamarefork()
La funzione crea un nuovo processo.
Dichiarazione di funzione:
pid_t fork(void);
Dipende dafork()
Il nuovo processo creato è chiamato processo figlio.
fork()
La funzione viene chiamata una volta ma restituisce due volte. La differenza tra i due valori restituiti è che il valore restituito del processo figlio è 0, mentre il valore restituito del processo padre è l'ID del processo figlio appena creato.
Il processo figlio e il processo padre continuano ad essere eseguitifork()
Il codice successivo, Il processo figlio è una copia del processo genitore. Il processo figlio ha una copia dello spazio dati, dell'heap e dello stack del processo genitore (nota: il processo figlio possiede una copia, non condivisa con il processo genitore).
fork()
Successivamente, l'ordine di esecuzione dei processi genitore e figlio non è definito.
fork()
, lascia che il processo figlio gestisca queste richieste, mentre il processo genitore continua ad attendere la successiva richiesta di connessione.fork()
Chiamato subito dopo il rientroexec
。fork()
Una caratteristica è che i descrittori di file aperti nel processo genitore verranno copiati nel processo figlio e il processo genitore e il processo figlio condividono lo stesso offset di file.
Se un processo genitore e un processo figlio scrivono su un file puntato dallo stesso descrittore senza alcuna forma di sincronizzazione, il loro output potrebbe essere mescolato tra loro.
A questo punto puoi vedere che ci sono solo 100.000 righe di dati.
In questo momento, dovrebbero esserci 200.000 righe di dati. Una riga in meno potrebbe essere dovuta al fatto che l'operazione di scrittura del file non è atomica. In assenza di un meccanismo di sincronizzazione, due processi potrebbero tentare di scrivere parti diverse del file contemporaneamente. causando il fallimento della scrittura.
vfork()
Le chiamate di funzione e i valori restituiti sono gli stessi difork()
Uguale, ma la loro semantica è diversa.
vfork()
La funzione viene utilizzata per creare un nuovo processo il cui scopo èexec
Un nuovo programma che non copia lo spazio degli indirizzi del processo genitore perché il processo figlio chiama immediatamenteexec
, quindi lo spazio degli indirizzi del processo genitore non verrà utilizzato. Se il processo figlio utilizza lo spazio degli indirizzi del processo padre, potrebbero verificarsi risultati sconosciuti.
vfork()
Efork()
Un'altra differenza è:vfork()
Assicurati che il processo figlio venga eseguito per primo e chiamalo nel processo figlioexec
Oexit
Quindi il processo genitore riprende l'operazione.
Nel sistema operativo, un processo zombie si riferisce a un processo figlio che è terminato ma il suo processo genitore non ha ancora letto il suo stato di uscita. Sebbene il processo zombie non sia più in esecuzione, occupa ancora una voce nella tabella dei processi in modo che il kernel possa salvare le informazioni sullo stato di uscita del processo (come ID del processo, stato di uscita, ecc.) finché il processo genitore non legge queste informazioni.
Se il processo genitore termina prima del processo figlio, il processo figlio sarà ospitato dal processo 1 (questo è anche un modo per consentire l'esecuzione del processo in background).
Se il processo figlio termina prima del processo genitore e il processo genitore non elabora le informazioni di uscita del processo figlio, allora il processo figlio diventerà un processo zombie.
Il kernel conserva una struttura dati per ogni processo figlio, incluso il numero del processo, lo stato di terminazione, il tempo della CPU utilizzato, ecc. Se il processo genitore elabora le informazioni di uscita del processo figlio, il kernel rilascerà questa struttura dati. Se il processo genitore non elabora le informazioni di uscita del processo figlio, il kernel non rilascerà questa struttura dati e il numero di processo del processo figlio sarà sempre occupato. I numeri di processo disponibili nel sistema sono limitati Se viene generato un numero elevato di processi zombie, il sistema non sarà in grado di generare nuovi processi perché non sono disponibili numeri di processo.
signal(SIGCHLD, SIG_IGN)
Notifica al kernel che non è interessato all'uscita del processo figlio e la sua struttura dati verrà rilasciata immediatamente dopo l'uscita del processo figlio.wait()
/waitpid()
funzione: Il processo genitore attende la fine del processo figlio chiamando queste funzioni e ottiene il suo stato di uscita, liberando così le risorse occupate dal processo figlio.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);
Il valore restituito è il numero del processo figlio.
stat_loc
Le informazioni sulla terminazione del processo figlio sono:
a) Se terminata normalmente, la macro WIFEXITED(stat_loc)
Restituisce vero, macroWEXITSTATUS(stat_loc)
È possibile ottenere lo stato di risoluzione;
b) Se termina in modo anomalo, la macro WTERMSIG(stat_loc)
Ottiene il segnale per terminare il processo.
Se il processo principale è occupato, puoi acquisire SIGCHLD
Segnale, richiamato nella funzione di elaborazione del segnalewait()
/waitpid()
。
[Invia segnali tra processi](##1.5 Invia segnali)
In un programma di servizio multiprocesso, se il sottoprocesso riceve un segnale di uscita, uscirà da solo.
Se il processo genitore riceve un segnale di uscita, dovrebbe inviare segnali di uscita a tutti i processi figli e poi uscire da solo.
I multi-thread condividono lo spazio degli indirizzi di un processo,Se più thread devono accedere alla stessa memoria, utilizza semplicemente le variabili globali.。
In più processi, lo spazio degli indirizzi di ciascun processo è indipendente e non condiviso.Se più processi devono accedere alla stessa memoria, non è possibile utilizzare le variabili globali, è possibile utilizzare solo la memoria condivisa.。
La memoria condivisa consente a più processi (non è richiesta alcuna relazione di sangue tra processi) di accedere allo stesso spazio di memoria. È il modo più efficace per condividere e trasferire dati tra più processi. I processi possono connettere la memoria condivisa al proprio spazio di indirizzi. Se un processo modifica i dati nella memoria condivisa, cambieranno anche i dati letti da altri processi.
La memoria condivisa non fornisce un meccanismo di blocco, vale a dire, quando un processo legge/scrive la memoria condivisa, non impedisce ad altri processi di leggerla/scriverla.Se vuoi bloccare la lettura/scrittura della memoria condivisa, puoi usare un semaforo . Linux fornisce una serie di funzioni per il funzionamento della memoria condivisa.
Questa funzione viene utilizzata per creare/acquisire memoria condivisa.
int shmget(key_t key, size_t size, int shmflg);
typedef unsigned int key_t
), generalmente in esadecimale, ad esempio 0x5005
, le chiavi di diverse memorie condivise non possono essere le stesse.0666|IPC_CREAT
Indica che se la memoria condivisa non esiste, crearla.utilizzo ipcs -m
È possibile visualizzare la memoria condivisa del sistema, tra cui: chiave, ID memoria condivisa (shmid), proprietario, autorizzazioni (permanenti) e dimensione (byte).
utilizzo ipcrm -m 共享内存id
La memoria condivisa può essere cancellata manualmente come segue:
Nota: i contenitori non possono essere utilizzati per i tipi di dati nella memoria condivisa, è possibile utilizzare solo i tipi di dati di base.
Questa funzione viene utilizzata per connettere la memoria condivisa allo spazio degli indirizzi del processo corrente.
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmget()
L'identificatore di memoria condivisa restituito dalla funzione.Restituisce l'indirizzo iniziale della memoria condivisa quando la chiamata ha esito positivo e restituisce quando fallisce. (void *)-1
。
Questa funzione viene utilizzata per staccare la memoria condivisa dal processo corrente, che è equivalente a shmat()
L'operazione inversa di una funzione.
int shmdt(const void *shmaddr);
shmat()
L'indirizzo restituito dalla funzione.Restituisce 0 se la chiamata ha esito positivo e -1 se fallisce.
Questa funzione viene utilizzata per gestire la memoria condivisa. L'operazione più comunemente utilizzata è eliminare la memoria condivisa.
int shmctl(int shmid, int command, struct shmid_ds *buf);
shmget()
L'ID della memoria condivisa restituito dalla funzione.IPC_RMID
。Restituisce 0 se la chiamata ha esito positivo e -1 se fallisce.
Nota, usa root
La memoria condivisa creata non può essere eliminata dagli utenti ordinari indipendentemente dalle autorizzazioni create.
Restituisce 0 se la chiamata ha esito positivo e -1 se fallisce.
Questa funzione viene utilizzata per gestire la memoria condivisa. L'operazione più comunemente utilizzata è eliminare la memoria condivisa.
int shmctl(int shmid, int command, struct shmid_ds *buf);
shmget()
L'ID della memoria condivisa restituito dalla funzione.IPC_RMID
。Restituisce 0 se la chiamata ha esito positivo e -1 se fallisce.
Nota, usa root
La memoria condivisa creata non può essere eliminata dagli utenti ordinari indipendentemente dalle autorizzazioni create.
[Le immagini del collegamento esterno sono in fase di trasferimento...(img-v6qW3XRA-1720711279572)]
[Le immagini del collegamento esterno sono in fase di trasferimento...(img-CG0tGAne-1720711279572)]