Comunicación entre procesos de Linux | comunicación de señales

Comunicación de señales

1. Descripción general de la señal

La señal es una simulación del mecanismo de interrupción a nivel de software. En principio, se puede decir que un proceso recibe una señal y el procesador recibe una solicitud de interrupción. La señal es asíncrona: un proceso no tiene que esperar la llegada de la señal a través de ninguna operación. La señal puede llevar a cabo directamente la interacción entre el proceso del espacio del usuario y el proceso del kernel, y el proceso del kernel también puede usarla para notificar al proceso del espacio del usuario qué eventos del sistema han ocurrido. Se puede enviar a un proceso en cualquier momento sin conocer el estado del proceso. Si el proceso no se encuentra actualmente en el estado de ejecución, el kernel guarda la señal hasta que el proceso reanuda la ejecución y luego se le pasa; si una señal está configurada para ser bloqueada por el proceso, la transmisión de la señal se retrasa hasta que se bloquea. Se pasa al proceso cuando se cancela.
La señal es el único mecanismo de comunicación asíncrono en el mecanismo de comunicación entre procesos. Puede pensar en este mecanismo como una notificación asincrónica para notificar al proceso que recibe la señal lo que sucedió. Los eventos de señal se pueden generar a partir de fuentes de hardware (como pulsaciones de teclas o fallas de hardware) y fuentes de software (kill (), raise (), alarm (), setitimer (), sigqueue (), etc., así como algunas operaciones ilegales).
El proceso puede responder a una señal de 3 formas:

  • Ignore la señal: no haga nada con la señal. Las señales SIGKILL y SIGSTOP no se pueden ignorar
  • Captura de señal: define la función de procesamiento de señal, ejecuta la función de procesamiento correspondiente cuando se produce la señal
  • Modo predeterminado: Linux proporciona operaciones predeterminadas para cada señal, como se muestra en la siguiente tabla
Nombre de la señal sentido Acción por defecto
SIGHUP Se envía cuando finaliza la conexión del terminal de usuario, notificando que cada proceso en la misma sesión ya no está asociado con el terminal de control Terminar el proceso
SIGNO Emitido cuando se ingresa el carácter INTR (Ctrl + C) y enviado a cada proceso del proceso de primer plano Terminar el proceso
SIGQUIT Similar a SIGINT, pero con el carácter QUIT (Ctrl + \) para controlar Terminar el proceso
SELLO Emitido cuando un proceso intenta ejecutar una instrucción ilegal Terminar el proceso
SIGFPE Emitido cuando ocurre una operación aritmética fatal Terminar el proceso
SIGKILL Se utiliza para finalizar la ejecución del programa inmediatamente y no puede bloquearse, procesarse ni ignorarse. Terminar el proceso
SIGALARM Emitido cuando expira un temporizador Terminar el proceso
SIGSTOP Se utiliza para suspender un proceso y no se puede bloquear, procesar ni ignorar. Pausar el proceso
SIGTSTP Se utiliza para detener el proceso de forma interactiva, emitido cuando el usuario ingresa el carácter SUSP (Ctrl + Z) Terminar el proceso
SIGCHLG Cuando el proceso hijo cambia de estado, el proceso padre recibirá esta señal ignorar

2. Función de correlación de señales

2.1 Envío de señal: kill () y raise ()

La función kill () es la misma que el comando kill system, puede enviar una señal al proceso o al grupo de procesos (el comando kill system es implementado por la función kill ()). Esta función no solo puede terminar el proceso, sino también enviar otras señales al proceso.
La función raise () solo permite que el proceso se envíe señales a sí mismo.

/*****kill()函数*****/
函数原型:int kill(pid_t pid, int sig)
传 入 值:pid -->正数:发送信号给进程号为pid的进程
			 --> 0:信号被发送到所有和当前进程在同一个进程组的进程
			 -->-1:信号发给所有的进程表中的进程(除了进程号最大的进程外)
			 -->小于-1:信号发送给进程组号为-pid的每一个进程
		  sig 信号类型
返 回 值:成功返回0;失败返回-1

/*****raise()函数*****/
函数原型:int raise(int sig)
传 入 值:sig 信号类型
返 回 值:成功返回0;失败返回-1

Programa de ejemplo

/*****kill_raise.c*****/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(){
    
    
	pid_t pid;
	int ret;
	
	if((pid == fork()) < 0){
    
    	//创建子进程
		printf("Fork error\n");
		exit(-1);
	}

	if(pid == 0){
    
    
		/*在子进程中使用raise()函数发出SIGSTOP信号,使子进程暂停*/
		printf("child(pid: %d) is waiting for any signal!\n",getpid());
		raise(SIGSTOP);
		exit(0);
	}else{
    
    
		/*在父进程中收集子进程的状态,并调用kill()函数发送信号*/
		if((waitpid(pid,NULL,WNOHANG)) == 0){
    
    
			kill(pid,SIGKILL);
			printf("parent kill child process %d\n",pid);
		}
		waitpid(pid,NULL,0);
		exit(0);
	}
}

Los resultados del programa son los siguientes

linux@linux-virtual-machine:~/andy/proc$ ./kill_raise
child(pid:4877) is waiting for any signal!
parent kill child process 4877
2.2 Señales del temporizador: alarma () y pausa ()

alarm () también se denomina función de alarma, puede configurar un temporizador en el proceso. Cuando expira el tiempo especificado por el temporizador, envía una señal SIGALARM al proceso. Cabe señalar que un proceso sólo puede tener una hora de alarma. Si la hora de alarma se ha configurado antes de llamar a la alarma (), cualquier hora de alarma anterior será reemplazada por el nuevo valor.
pause () se usa para suspender el proceso de llamada hasta que se reciba la señal.

/*****alarm()函数*****/
函数原型:unsigned int alarm(unsigned int seconds)
传 入 值:seconds 指定秒数,系统经过seconds秒后向该进程发送SIGALARM信号
返 回 值:成功:如果调用此函数前,进程中已经设置了闹钟时间,则返回上一个闹钟剩余的时间,否则返回0
		 失败:返回-1

/*****pause()函数*****/
函数原型:int pause(void)
返 回 值:-1 并且把errno值设为EINTR

Programa de ejemplo

/*****alarm_pause.c*****/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(){
    
    
	alarm(5);
	pause();
	printf("I have been waken up\n");	//此语句不会被执行
}

Los resultados del programa son los siguientes

linux@linux-virtual-machine:~/andy/proc$ ./alarm_pause
Alarm clock		//SIGALARM信号默认处理函数打印
2.3 Configuraciones de señal: señal () y sigaction ()

Hay dos métodos principales de procesamiento de señales: uno es usar una función simple signal () y el otro es usar sigaction ().
La función signal () solo necesita especificar el tipo de señal y la función de procesamiento de señal. Se utiliza principalmente para procesar los primeros 32 tipos de señales en tiempo no real y no admite la transmisión de información por señales.
La función sigaction () es más robusta y más versátil que la función signal ().

/*****signal()函数*****/
函数原型:typedef void (*sighandler_t)(int);
		 sighandler_t signal(int signum,sighandler_t handler);
传 入 值:signum 指定信号代码
		 handler -->SIG_IGN 忽略该信号
		         -->SIG_DFL 采用系统默认方式处理信号
		         -->自定义的信号处理函数
返 回 值:成功:返回以前的信号处理函数
		 失败:返回-1

/*****sigaction()函数*****/
函数原型:int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
传 入 值:signum 信号类型,除SIGKILL和SIGSTOP之外的任何一个信号
		 act 指向sigaction结构体的指针,包含对特点信号的处理
		 oldact 保存信号原先的处理方式
返 回 值:成功返回0;失败返回-1

//sigaction结构体的定义
struct sigaction{
    
    
	void (*sa_handler)(int signo); //函数指针,指向信号处理函数
	sigset_t sa_mask;  //信号集合,用来指定在信号处理函数执行过程中哪些信号被屏蔽
	int sa_flags;  //信号处理相关的各种标志位
	void (*sa_restore)(void);
}

señal () programa de ejemplo

/*****signal.c*****/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void my_func(int sign_no){
    
    	//自定义信号处理函数
	if(sign_no == SIGINT)
		printf("I have got SIGINT\n");
	else if(sign_no == SIGQUIT)
		printf("I have got SIGQUIT\n");
}

int main(){
    
    
	printf("Waiting for signal SIGINT or SIGQUIT...\n");
	signal(SIGINT,my_func);
	signal(SIGQUIT,my_func);
	pause();
	exit(0);	
}

Los resultados del programa son los siguientes

linux@linux-virtual-machine:~/andy/proc$ ./signal
Waiting for signal SIGINT or SIGQUIT...
I have got SIGINT (按 ctrl + c 组合键)
linux@linux-virtual-machine:~/andy/proc$ ./signal
Waiting for signal SIGINT or SIGQUIT...
I have got SIGQUIT (按 ctrl + \ 组合键)

sigaction () programa de ejemplo para lograr la misma función

/*****sigaction.c*****/
//头文件省略
//自定义信号处理函数同以上实例
int main(){
    
    
	struct sigaction action;
	/*sigaction结构初始化*/
	sigaction(SIGINT,0,&action);
	action.sa_handler = my_func;
	sigaction(SIGINT,&action,0);

	sigaction(SIGQUIT,0,&action);
	action.sa_handler = my_func;
	sigaction(SIGQUIT,&action,0);
	printf("Waiting for signal SIGINT or SIGQUIT...\n");

	pause();
	exit(0);	
}

Supongo que te gusta

Origin blog.csdn.net/Chuangke_Andy/article/details/108305697
Recomendado
Clasificación