SIGNAL
Signals appeared in early Unix, and the early signal model is unreliable. BSD and System V extend the early signals respectively, but they are incompatible with each other. POSIX unifies the above two models, thus providing a reliable signal model.
1. Basic concept of signal
- It is used for communication between processes. It can interrupt the running process of the process and change the processing flow
Process 1 sends a signal to process 2. Process 2 stops the current work and processes the signal instead to execute the corresponding work
- The signal is a software interrupt
- Signals are asynchronous events
Process 1 sends a signal to process 2. Process 1 does not need to wait for a response from process 2 and will continue to perform its own tasks.
- Unforeseen - The signal has its own name and number, such as SIGINT - Signal and exception handling mechanism
see linux Name and number of signals in the system, using kill -l Command.
The signal has no priority. 1~31 For non real-time signals, the transmitted signals may be lost and signal queuing is not supported. ( linux Used in the operating system, recorded in/usr/include/bits/signum.h In the file,Each signal has a certain explanation) 34~64 Real time signal, support signal queuing, and multiple real-time signals sent will be received.
- Source of signal generation
Hardware source (driven by hardware) 1. Press the keyboard. CTRL+C CTRL+Z wait. 2. Some other hardware faults are caused by the hardware driver. Software source (generated by kernel) 1. Common system functions for sending signals: kill(),raise(),alarm(),settimer()Wait. 2. Some illegal operations. Divide by 0, floating point arithmetic error, etc. 3. Software setting conditions (e.g gdb).
2. Three signal processing methods
2.1. Ignore signal (signal, sig_ign)
SIGKILL and SIGSTOP It can never be ignored and cannot be captured. It's no use setting it. Can be used to ignore hardware exception signals. When the process starts, SIGUSR1 and SIGUSR2 Both signals are ignored by default. Register it and it can be captured and processed.
2.2. Execute the default operation signal(signo,SIG_DEF)
Each signal has its own default action, and the default action of most signals is to terminate the process.
2.3. Capture signal (signal, func)
Tell the kernel to call its own processing function when a signal occurs. signal Used to register signals and processing functions with the kernel. SIGKILL and SIGSTOP Cannot be captured and ignored. Only default operations can be performed.
2.4 signal function
View the signal function and use the man signal command.
#include <signal.h> void (*signal( int signo, void (*func)(int) ))(int); Function: register and install signal processing functions to the kernel. Return: the pointer of the signal processing function is returned successfully, and the error is returned SIG_ERR Parameters: signo The signal value to be registered, func Signal processing function pointer or SIG_IGN Ignore signal or SIG_DEF Perform the default action.
2.5 reference examples
Capture and register SIGTSTP and SIGINT
#include <signal.h> #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <unistd.h> //Define signal processing functions //signo: signal captured by the process void sig_handler(int signo) { printf("%d,%d occured\n",getpid(),signo); } int main(void) { //Register the signal processing function and signal value with the kernel if(signal(SIGTSTP,sig_handler) == SIG_ERR){ perror("signal sigtstp error"); } if(signal(SIGINT,sig_handler) == SIG_ERR){ perror("signal sigint error"); } int i=0; while(i<30) { printf("%d out %d\n",getpid(),i++); sleep(1);//1 second } }
After compiling and running, the keyboard combination CTRL+C CTRL+Z can no longer exit the interrupt.
kshine@kshine-virtual-machine:~/desktop $ gcc test.c -o bin kshine@kshine-virtual-machine:~/desktop $ ./bin 6116 out 0 6116 out 1 6116 out 2 6116 out 3 6116 out 4 6116 out 5 6116 out 6 6116 out 7 6116 out 8 6116 out 9 6116 out 10 ^C6116,2 occured //CTRL+C terminate 6116 out 11 6116 out 12 6116 out 13 6116 out 14 ^C6116,2 occured //CTRL+C terminate 6116 out 15 6116 out 16 6116 out 17 6116 out 18 ^Z6116,20 occured //CTRL+Z pause 6116 out 19 6116 out 20 6116 out 21 6116 out 22 6116 out 23 6116 out 24 6116 out 25 ^C6116,2 occured //CTRL+C terminate 6116 out 26 6116 out 27 6116 out 28 6116 out 29
2.6 how can signals be used
have access to kill -SIGCONT Process number to enable a process to resume operation. You can also use kill -SIGSTP Process number to pause a process. and CTRL+Z Same function.
signal(SIGINT,SIG_IGN); //Can be used to ignore CTRL+C signals
signal(SIGINT,SIG_DFL); //The CTRL+C signal is used to terminate the process by default
2.7 SIGCHLD signal
In the learning process, I mentioned that in order to avoid zombie processes, there are two ways to close sub processes. First, the parent process uses wait() to block and wait for the child process to end and recycle. Second, the parent process ends, and process 1 takes the adopted child process and reclaims it.
Here, we can also use sigshield signal to reclaim sub processes in time. This allows the parent process to continue running without waiting for the child process to finish.
#include <signal.h> #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <sys/wait.h> //Define signal processing functions //signo: signal captured by the process void sig_handler(int signo) { printf("child processs dead, signo:%d\n",signo); //When the subprocess ends, SIGCHID signal will be generated. The parent process captures and wait s for the child process resources. wait(0); } void out(int n) { int i; for(i=0;i<n;i++) { printf("%d out %d\n",getpid(),i); sleep(2); } } int main(void) { //Register the signal processing function and signal value with the kernel if(signal(SIGCHLD,sig_handler) == SIG_ERR){ perror("signal sigchld error"); } pid_t pid = fork(); if(pid<0){ perror("fork error"); exit(1); }else if(pid>0){//Parent process out(100); }else if(pid==0){//Subprocess out(10); } }
Operation results:
kshine@kshine-virtual-machine:~/desktop $ gcc test.c -o bin kshine@kshine-virtual-machine:~/desktop $ ./bin 9078 out 0 9079 out 0 9078 out 1 9079 out 1 9078 out 2 9079 out 2 9078 out 3 9079 out 3 9078 out 4 9079 out 4 9078 out 5 9079 out 5 9078 out 6 9079 out 6 9078 out 7 9079 out 7 9078 out 8 9079 out 8 9078 out 9 9079 out 9 9078 out 10 child processs dead, signo:17 9078 out 11 9078 out 12 9078 out 13 9078 out 14 9078 out 15 ^C kshine@kshine-virtual-machine:~/desktop $
3. Signal transmission
3.1 basic concepts
- Not all processes except the kernel and superuser root can send signals to other processes.
- General processes can only send signals to processes with the same uid (user ID, created by the same user) and gid (user group ID, belonging to the same user group), or to other processes in the same process group.
3.1.1 function of transmitting signal
- kill() sends signals to other processes or yourself. You can use man 2 kill to view the function introduction.
#include <sys/types.h> #include <signal.h> /* sig It can be a null signal of 0 to detect whether a specific signal exists. pid Process number. (1)pid>0 Process ID (2)pid ==0,Send signals to all processes in the same process group. (3)pid < 0 Send a signal to all processes whose process group ID is equal to the absolute value of pid (4)pid==-1 Send the signal to all processes on the system that the sending process has permission to send the signal. */ int kill(pid_t pid, int sig);
- raise() can only send signals to itself
#include <signal.h> int raise(int sig);
Reference examples:
#include <signal.h> #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <unistd.h> //Define signal processing functions //signo: signal captured by the process void sig_handler(int signo) { printf("signo:%d\n",signo); } int main(void) { //Register the signal processing function and signal value with the kernel if(signal(SIGUSR1,sig_handler) == SIG_ERR){ perror("signal sigusr1 error"); } if(signal(SIGUSR2,sig_handler) == SIG_ERR){ perror("signal sigusr2 error"); } int i=0; while(i<10){ printf("%d out %d\n",getpid(),i++); //if(i==5) kill(getpid(),SIGKILL); // Kill yourself sleep(1); } //Send a signal to the process itself raise(SIGUSR1); kill(getpid(),SIGUSR2); }
kshine@kshine-virtual-machine:~/desktop $ gcc test.c -o bin kshine@kshine-virtual-machine:~/desktop $ ./bin 9567 out 0 9567 out 1 9567 out 2 9567 out 3 9567 out 4 9567 out 5 9567 out 6 9567 out 7 9567 out 8 9567 out 9 signo:10 signo:12 kshine@kshine-virtual-machine:~/desktop $
- Alarm timing signal
Set the timer. When the timer times out, SIGALRM signal will be generated.
It is not a periodic timing signal, but a one-time signal.
The accuracy is only seconds. To use higher accuracy, you can use the ualarm() function.
#include <unistd.h> /* seconds ==0 The previously set timer can be cancelled. */ unsigned int alarm(unsigned int seconds);
Reference examples:
#include <signal.h> #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <math.h> //Define signal processing functions //signo: signal captured by the process void sig_handler(int signo) { if(signo == SIGALRM){ printf("clock time out\n"); //Reset timer (periodic timing) alarm(5); } } void out(void) { int i=0; while(i<20) { double d = drand48(); printf("%-10d:%lf\n",i++,d); //if(i==16) alarm(0);// Cancel timer sleep(1); } } int main(void) { //Register the signal processing function and signal value with the kernel if(signal(SIGALRM,sig_handler) == SIG_ERR){ perror("signal sigalrm error"); } //set timer alarm(5); printf("begin running main\n"); out(); printf("end running main\n"); return 0; }
Operation results:
kshine@kshine-virtual-machine:~/desktop $ gcc test.c -o bin kshine@kshine-virtual-machine:~/desktop $ ./bin begin running main 0 :0.000000 1 :0.000985 2 :0.041631 3 :0.176643 4 :0.364602 clock time out 5 :0.091331 6 :0.092298 7 :0.487217 8 :0.526750 9 :0.454433 clock time out 10 :0.233178 11 :0.831292 12 :0.931731 13 :0.568060 14 :0.556094 clock time out 15 :0.050832 16 :0.767051 17 :0.018915 18 :0.252360 19 :0.298197 clock time out end running main kshine@kshine-virtual-machine:~/desktop $
- settimer()
- abort() abnormal termination generates SIGABRT
4. High order lifting
4.1 signal reliability
- Unreliable signal problem I
When a signal occurs, bind the signal again in the association action.
- During the time between entering the associated action and calling the signal binding again in the associated action, the signal may be lost, that is, the same signal will not be captured
- Cause the process to terminate
- Unreliable signal problem 2
Unable to pause blocking signal.