Mi informacion de contacto
Correo[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
La señal (señal) es una interrupción de software. Es un método para transmitir mensajes entre procesos. Se utiliza para notificar al proceso que ha ocurrido un evento, pero no puede pasar ningún dato al proceso.
Hay muchas razones por las que se generan señales en Shell.kill
ykillall
Comando para enviar señal:
kill -信号的类型 进程编号
killall -信号的类型 进程名
nombre de la señal | valor de la señal | Acción de procesamiento predeterminada | Razón de la señalización |
---|---|---|---|
SUSPIRO | 1 | A | El terminal se cuelga o el proceso de control finaliza |
SEÑAL | 2 | A | Interrupción del teclado Ctrl+c |
SALIRSE | 3 | C | Se presiona la tecla Escape del teclado. |
SIGIL | 4 | C | instrucción ilegal |
Trampa de señales | 5 | C | instrucciones de punto de interrupción |
SIGABRT | 6 | C | Señal de aborto emitida por aborto(3) |
SIGBUS | 7 | C | error de bus |
SIGFPE | 8 | C | excepción de punto flotante |
Matanza de señales | 9 | A | kill -9 mata el proceso, esta señal no se puede captar ni ignorar |
SIGUSR1 | 10 | A | Señal definida por el usuario 1 |
SIGSEGV | 11 | C | Referencia de memoria no válida (matriz fuera de límites, operación de puntero nulo) |
SIGUSR2 | 12 | A | Señal definida por el usuario 2 |
SIGPIPE | 13 | A | Escribir datos en una tubería sin un proceso de lectura. |
Señal | 14 | A | Señal de despertador, señal enviada por la función alarm() |
TÉRMINO DE SEGURIDAD | 15 | A | Señal de terminación, la señal enviada por defecto. |
Señal de advertencia | 16 | A | error de pila |
SEGURIDAD | 17 | B | Emitido cuando finaliza el proceso hijo. |
Control de señal | 18 | D | Reanudar un proceso detenido |
PARADA DE SEÑAL | 19 | D | Detener proceso |
SIGTSTP | 20 | D | Pulsar la tecla de parada del terminal |
SIGNIFICADO | 21 | D | Solicitudes de proceso en segundo plano para leer el terminal |
Señal | 22 | D | El proceso en segundo plano solicita escribir en la terminal. |
Sigurg | 23 | B | Detección de condiciones de emergencia (enchufes) |
CPU SIGX | 24 | C | Se superó el límite de tiempo de CPU |
SIGXFSZ | 25 | C | Excede el límite de tamaño de archivo |
SEÑAL DE SEGURIDAD | 26 | A | señal de reloj virtual |
SIGPROF | 27 | A | Analizar señales de reloj. |
CABRESTANTE DE SEÑAL | 28 | B | Cambios de tamaño de ventana |
ENCUESTA DE SIG | 29 | B | Sondeo (Sistema V) |
SIGPWR | 30 | A | falla electrica |
SIGSYS | 31 | C | Llamada ilegal al sistema |
La acción predeterminada de A es terminar el proceso.
La acción predeterminada de B es ignorar esta señal.
La acción predeterminada de C es finalizar el proceso y realizar un volcado de la imagen del kernel.
La acción predeterminada de D es detener el proceso y el programa que ingresa al estado detenido puede continuar ejecutándose.
Hay tres formas en que los procesos manejan señales:
signal()
Las funciones pueden establecer cómo el programa maneja las señales.
Declaración de función:
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
Descripción de parámetros:
sig
:Especifique la señal a capturar.func
: Puntero a la función de procesamiento de señales. La función de procesamiento necesita recibir un parámetro entero, que es el número de señal capturada.SIG_DFL
La macro :SIG_DFL representa el método de procesamiento de señales predeterminado.usarSIG_DFL
comosignal
El segundo parámetro de la función indica que se utiliza el método de procesamiento predeterminado del sistema para la señal.SIG_IGN
La macro :SIG_IGN significa ignorar la señal.usarSIG_IGN
comosignal
El segundo parámetro de la función indica que cuando el proceso reciba la señal, la ignorará y no realizará ningún procesamiento. Esto puede evitar que los procesos finalicen o se interrumpan inesperadamente en determinadas circunstancias.SIG_ERR
:SIG_ERR
Las macros se utilizan para indicar errores.no es comosignal
El segundo parámetro de la función se utiliza en su lugar comosignal
El valor de retorno de la función indica que la llamada falló.sisignal
Si la llamada a la función falla, devolveráSIG_ERR
.Normalmente se utiliza para detectar y procesarsignal
Error en llamada a función.El programa de servicio se ejecuta en segundo plano. Si desea detenerlo, no es una buena idea matarlo, porque cuando el proceso finaliza, muere repentinamente y no se realizan trabajos posteriores.
Si envía una señal al programa de servicio, después de recibir la señal, el programa de servicio llama a una función y escribe el código posterior en la función, y el programa puede salir de forma planificada.
Enviar una señal de 0 al programa de servicio puede detectar si el programa está activo.
El sistema operativo Linux proporciona kill
ykillall
El comando envía una señal al programa. En el programa, puedes usar.kill()
Las funciones de la biblioteca envían señales a otros procesos.
Declaración de función:
int kill(pid_t pid, int sig);
kill()
La función toma los parámetros.sig
La señal especificada se pasa al parámetro.pid
proceso especificado.
parámetro pid
Hay varias situaciones:
pid > 0
Pasar la señal al proceso comopid
proceso.pid = 0
Pasar la señal a todos los procesos en el mismo grupo de procesos que el proceso actual. A menudo lo utiliza el proceso padre para enviar señales al proceso hijo. Tenga en cuenta que este comportamiento depende de la implementación del sistema.pid < -1
Pasar la señal al ID del grupo de proceso de|pid|
de todos los procesos.pid = -1
Pasa la señal a todos los procesos que tienen permiso para enviar la señal, pero no al proceso que envió la señal.Existen 8 formas de finalizar un proceso, 5 de las cuales son terminaciones normales, son:
main()
Para funcionesreturn
devolver;exit()
función;_exit()
o_Exit()
función;return
devolver;pthread_exit()
devolver;Hay tres formas de terminar de forma anormal, son:
abort()
aborto de función;existir main()
En la función,return
El valor devuelto es el estado de terminación, si noreturn
declaración o llamadaexit()
, entonces el estado de terminación del proceso es 0.
En el shell, vea el estado de terminación del proceso:
echo $?
3 funciones para finalizar el proceso normalmente (exit()
y_Exit()
está especificado por ISO C,_exit()
está especificado por POSIX):
void exit(int status);
void _exit(int status);
void _Exit(int status);
status
El estado de terminación del proceso.
return
Indica que cuando la función regrese, se llamará al destructor del objeto local.main()
en funciónreturn
También se llama al destructor del objeto global.exit()
Indica que para finalizar el proceso, no se llamará al destructor del objeto local, solo se llamará al destructor del objeto global._exit()
y_Exit()
Salga directamente y no se realizará ningún trabajo de limpieza.El proceso está disponible. atexit()
El registro de funciones finaliza las funciones (hasta 32), estas funciones seexit()
Llamado automáticamente.
int atexit(void (*function)(void));
exit()
El orden en que se invocan las funciones de terminación se invierte desde el momento del registro.
system()
La función proporciona un método simple para ejecutar el programa, pasando el programa y los parámetros que deben ejecutarse como una cadena.system()
Simplemente funciona.
Declaración de función:
int system(const char * string);
system()
El valor de retorno de la función es más problemático.
system()
La función devuelve un valor distinto de cero;system()
La función devuelve 0;system()
La función devuelve un valor distinto de cero.exec
Las familias de funciones proporcionan otra forma de llamar programas (binarios o scripts de shell) dentro de un proceso.
exec
La familia de funciones se declara de la siguiente manera:
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[]);
Aviso:
errno
medio.exec
Después de eso, el programa llamado reemplazará al programa que llama, es decir,exec
No se ejecutará ningún código después de la función.execl()
yexecv()
, otros rara vez se utilizan.Todos los procesos en todo el sistema Linux están en una estructura de árbol.
usarpstree
Puede ver el árbol de procesos con el comando:
pstree -p 进程编号
Cada proceso tiene un ID de proceso único representado por un número entero no negativo. Aunque son únicos, los ID de proceso se pueden reutilizar. Cuando un proceso finaliza, su ID de proceso se convierte en candidato para su reutilización. Linux utiliza un algoritmo de reutilización retrasada para que la ID de un proceso recién creado sea diferente de la ID utilizada por el proceso finalizado recientemente. Esto evita que los procesos nuevos se confundan con un proceso terminado que utiliza el mismo ID.
Función para obtener ID del proceso:
pid_t getpid(void); // 获取当前进程的ID。
pid_t getppid(void); // 获取父进程的ID。
Un proceso existente puede llamarfork()
La función crea un nuevo proceso.
Declaración de función:
pid_t fork(void);
Depender defork()
El nuevo proceso creado se denomina proceso hijo.
fork()
La función se llama una vez pero regresa dos veces. La diferencia entre los dos retornos es que el valor de retorno del proceso hijo es 0, mientras que el valor de retorno del proceso padre es el ID del proceso hijo recién creado.
El proceso hijo y el proceso padre continúan ejecutándose.fork()
El código después de eso, El proceso hijo es una copia del proceso padre. El proceso hijo tiene una copia del espacio de datos, el montón y la pila del proceso padre (nota: el proceso hijo posee una copia, no la comparte con el proceso padre).
fork()
Después de eso, el orden de ejecución de los procesos padre e hijo no está definido.
fork()
, deje que el proceso hijo maneje estas solicitudes, mientras el proceso padre continúa esperando la siguiente solicitud de conexión.fork()
Llamado inmediatamente después del regreso.exec
。fork()
Una característica es que los descriptores de archivos abiertos en el proceso principal se copiarán al proceso secundario, y el proceso principal y el proceso secundario comparten el mismo desplazamiento de archivo.
Si un proceso padre y un proceso hijo escriben en un archivo señalado por el mismo descriptor sin ningún tipo de sincronización, sus resultados pueden mezclarse entre sí.
En este punto puedes ver que sólo hay 100.000 filas de datos.
En este momento, debería haber 200.000 filas de datos. Una fila menos puede deberse a que la operación de escritura del archivo no es atómica. Sin un mecanismo de sincronización, dos procesos pueden intentar escribir diferentes partes del archivo al mismo tiempo. provocando que la escritura falle.
vfork()
Las llamadas a funciones y los valores de retorno son los mismos quefork()
Lo mismo, pero su semántica es diferente.
vfork()
La función se utiliza para crear un nuevo proceso cuyo propósito esexec
Un nuevo programa que no copia el espacio de direcciones del proceso padre porque el proceso hijo llama inmediatamenteexec
, por lo que no se utilizará el espacio de direcciones del proceso principal. Si el proceso hijo utiliza el espacio de direcciones del proceso padre, pueden producirse resultados desconocidos.
vfork()
yfork()
Otra diferencia es:vfork()
Asegúrese de que el proceso hijo se ejecute primero y llámelo en el proceso hijoexec
oexit
Luego, el proceso principal reanuda la operación.
En el sistema operativo, un proceso zombie se refiere a un proceso hijo que ha finalizado pero su proceso padre aún no ha leído su estado de salida. Aunque el proceso zombie ya no se está ejecutando, todavía ocupa una entrada en la tabla de procesos para que el kernel pueda guardar la información del estado de salida del proceso (como ID del proceso, estado de salida, etc.) hasta que el proceso principal lea esta información.
Si el proceso principal sale antes que el proceso secundario, el proceso secundario será alojado por el proceso 1 (esta también es una forma de permitir que el proceso se ejecute en segundo plano).
Si el proceso hijo sale antes que el proceso padre y el proceso padre no procesa la información de salida del proceso hijo, entonces el proceso hijo se convertirá en un proceso zombie.
El kernel conserva una estructura de datos para cada proceso hijo, incluido el número de proceso, el estado de terminación, el tiempo de CPU utilizado, etc. Si el proceso principal procesa la información de salida del proceso secundario, el kernel liberará esta estructura de datos. Si el proceso principal no procesa la información de salida del proceso secundario, el kernel no liberará esta estructura de datos y el número de proceso del proceso secundario siempre estará ocupado. Los números de proceso disponibles en el sistema son limitados. Si se genera una gran cantidad de procesos zombies, el sistema no podrá generar nuevos procesos porque no hay números de proceso disponibles.
signal(SIGCHLD, SIG_IGN)
Notifique al kernel que no está interesado en la salida del proceso hijo y que su estructura de datos se liberará inmediatamente después de que salga el proceso hijo.wait()
/waitpid()
función: El proceso padre espera a que finalice el proceso hijo llamando a estas funciones y obtiene su estado de salida, liberando así los recursos ocupados por el proceso hijo.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);
El valor de retorno es el número del proceso hijo.
stat_loc
¿La información sobre la terminación del proceso hijo es:
a) Si termina normalmente, la macro WIFEXITED(stat_loc)
Devuelve verdadero, macroWEXITSTATUS(stat_loc)
Se puede obtener el estado de terminación;
b) Si finaliza de forma anormal, la macro WTERMSIG(stat_loc)
Recibe la señal para finalizar el proceso.
Si el proceso principal está ocupado, puede capturar SIGCHLD
Señal, llamada en la función de procesamiento de señal.wait()
/waitpid()
。
[Enviar señales entre procesos](##1.5 Enviar señales)
En un programa de servicio multiproceso, si el subproceso recibe una señal de salida, el subproceso saldrá por sí solo.
Si el proceso principal recibe una señal de salida, debe enviar señales de salida a todos los procesos secundarios y luego salir él mismo.
Los subprocesos múltiples comparten el espacio de direcciones de un proceso,Si varios subprocesos necesitan acceder a la misma memoria, simplemente use variables globales.。
En múltiples procesos, el espacio de direcciones de cada proceso es independiente y no compartido.Si varios procesos necesitan acceder a la misma memoria, no se pueden usar variables globales, solo se puede usar memoria compartida.。
La memoria compartida permite que múltiples procesos (no se requiere ningún parentesco consanguíneo entre procesos) accedan al mismo espacio de memoria. Es la forma más efectiva de compartir y transferir datos entre múltiples procesos. Los procesos pueden conectar la memoria compartida a su propio espacio de direcciones. Si un proceso modifica los datos en la memoria compartida, los datos leídos por otros procesos también cambiarán.
La memoria compartida no proporciona un mecanismo de bloqueo, es decir, cuando un proceso lee/escribe en la memoria compartida, no impide que otros procesos la lean/escriban.Si desea bloquear la lectura/escritura de la memoria compartida, puede utilizar un semáforo . Linux proporciona un conjunto de funciones para operar la memoria compartida.
Esta función se utiliza para crear/adquirir memoria compartida.
int shmget(key_t key, size_t size, int shmflg);
typedef unsigned int key_t
), generalmente en hexadecimal, por ejemplo 0x5005
, las claves de diferentes recuerdos compartidos no pueden ser las mismas.0666|IPC_CREAT
Indica que si la memoria compartida no existe, crearla.usar ipcs -m
Puede ver la memoria compartida del sistema, incluida: clave, ID de memoria compartida (shmid), propietario, permisos (perms) y tamaño (bytes).
usar ipcrm -m 共享内存id
La memoria compartida se puede eliminar manualmente de la siguiente manera:
Nota: Los contenedores no se pueden usar para tipos de datos en la memoria compartida, solo se pueden usar tipos de datos básicos.
Esta función se utiliza para conectar la memoria compartida al espacio de direcciones del proceso actual.
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmget()
El identificador de memoria compartida devuelto por la función.Devuelve la dirección inicial de la memoria compartida cuando la llamada es exitosa y regresa cuando falla. (void *)-1
。
Esta función se utiliza para desconectar la memoria compartida del proceso actual, lo que equivale a shmat()
La operación inversa de una función.
int shmdt(const void *shmaddr);
shmat()
La dirección devuelta por la función.Devuelve 0 si la llamada tiene éxito y -1 si falla.
Esta función se utiliza para operar la memoria compartida. La operación más utilizada es eliminar la memoria compartida.
int shmctl(int shmid, int command, struct shmid_ds *buf);
shmget()
La identificación de la memoria compartida devuelta por la función.IPC_RMID
。Devuelve 0 si la llamada tiene éxito y -1 si falla.
Nota, uso root
Los usuarios normales no pueden eliminar la memoria compartida creada, independientemente de los permisos creados.
Devuelve 0 si la llamada tiene éxito y -1 si falla.
Esta función se utiliza para operar la memoria compartida. La operación más utilizada es eliminar la memoria compartida.
int shmctl(int shmid, int command, struct shmid_ds *buf);
shmget()
La identificación de la memoria compartida devuelta por la función.IPC_RMID
。Devuelve 0 si la llamada tiene éxito y -1 si falla.
Nota, uso root
Los usuarios normales no pueden eliminar la memoria compartida creada, independientemente de los permisos creados.
[Las imágenes del enlace externo se están transfiriendo...(img-v6qW3XRA-1720711279572)]
[Las imágenes del enlace externo se están transfiriendo...(img-CG0tGAne-1720711279572)]