Linux interprocess communication|signal communication

Signal communication

1. Signal overview

The signal is a simulation of the interrupt mechanism at the software level. In principle, it can be said that a process receives a signal and the processor receives an interrupt request. The signal is asynchronous: a process does not have to wait for the arrival of the signal through any operation. The signal can directly carry out the interaction between the user space process and the kernel process, and the kernel process can also use it to notify the user space process which system events have occurred. It can be sent to a process at any time without knowing the state of the process. If the process is not currently in the execution state, the signal is saved by the kernel until the process resumes execution and then passed to it; if a signal is set to be blocked by the process, the transmission of the signal is delayed until it is blocked It is passed to the process when it is cancelled.
Signal is the only asynchronous communication mechanism in the inter-process communication mechanism. You can think of this mechanism as an asynchronous notification to notify the process receiving the signal what happened. Signal events can be generated from hardware sources (such as keystrokes or hardware failures) and software sources (kill(), raise(), alarm(), setitimer(), sigqueue(), etc., as well as some illegal operations).
The process can respond to a signal in 3 ways:

  • Ignore the signal: do nothing to the signal. SIGKILL and SIGSTOP signals cannot be ignored
  • Capture signal: define signal processing function, execute corresponding processing function when signal occurs
  • Default mode: Linux provides default operations for each signal, as shown in the following table
Signal name meaning Default action
SIGHUP Sent when the user terminal connection ends, notifying that each process in the same session is no longer associated with the control terminal Terminate the process
SIGINT Emitted when the INTR character is input (Ctrl+C), and sent to each process of the foreground process Terminate the process
SIGQUIT Similar to SIGINT, but with QUIT character (Ctrl+ \) to control Terminate the process
SEAL Issued when a process attempts to execute an illegal instruction Terminate the process
SIGFPE Issued when a fatal arithmetic operation occurs Terminate the process
SIGKILL Used to end the running of the program immediately, and cannot be blocked, processed or ignored Terminate the process
SIGALARM Emitted when a timer expires Terminate the process
SIGSTOP Used to suspend a process, and cannot be blocked, processed or ignored Pause the process
SIGTSTP Used to interactively stop the process, issued when the user enters the SUSP character (Ctrl+Z) Terminate the process
SIGCHLG When the child process changes state, the parent process will receive this signal ignore

2. Signal correlation function

2.1 Signal sending: kill() and raise()

The kill() function is the same as the kill system command, it can send a signal to the process or process group (the kill system command is implemented by the kill() function). This function can not only terminate the process, but also send other signals to the process.
The raise() function only allows the process to send signals to itself.

/*****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

Example program

/*****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);
	}
}

The results of the program are as follows

linux@linux-virtual-machine:~/andy/proc$ ./kill_raise
child(pid:4877) is waiting for any signal!
parent kill child process 4877
2.2 Timer signals: alarm() and pause()

alarm() is also called the alarm function, it can set a timer in the process. When the time specified by the timer expires, it sends a SIGALARM signal to the process. It should be noted that a process can only have one alarm time. If the alarm time has been set before calling alarm(), any previous alarm time will be replaced by the new value.
pause() is used to suspend the calling process until the signal is received.

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

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

Example program

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

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

The results of the program are as follows

linux@linux-virtual-machine:~/andy/proc$ ./alarm_pause
Alarm clock		//SIGALARM信号默认处理函数打印
2.3 Signal settings: signal() and sigaction()

There are two main methods of signal processing: one is to use a simple signal() function, and the other is to use sigaction().
The signal() function only needs to specify the signal type and signal processing function. It is mainly used for processing the first 32 kinds of non-real-time signals, and does not support signal transmission of information.
The sigaction() function is more robust and more versatile than the signal() function.

/*****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);
}

signal() example program

/*****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);	
}

The results of the program are as follows

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() example program to achieve the same function

/*****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);	
}

Guess you like

Origin blog.csdn.net/Chuangke_Andy/article/details/108305697