Signals are the oldest way of communicating between Linux processes. The signal is a software interrupt, which is a simulation of the interrupt mechanism at the software level, and is an asynchronous communication method. Signals can cause a running process to be interrupted by another running asynchronous process to handle an unexpected event.
The signal we study here belongs to such an interrupt. When we hit Ctrl + c on the terminal, an interrupt is generated, which is equivalent to a signal, and then this interrupt task will be processed.
The characteristics of the signal:
1. Simple
2. Cannot carry a large amount of information
3. Only when a certain condition is met can it be sent
The signal can directly interact between the user space process and the kernel space process, and the kernel process can use it to notify the user space process of which system events have occurred.
A complete signal cycle includes three parts: the generation of the signal, the registration of the signal in the process, the cancellation of the signal in the process, and the execution of the signal processing function
signal number
The early version of Unix provided a signal mechanism, but it was unreliable and the signal might be lost. Later, the signal model was changed and a reliable signal mechanism was added, but they were incompatible with each other. POSIX.1 standardized the reliable signal routines
kill -l View signal numbers
Signals 1-31 are called regular signals (also known as ordinary signals or standard signals), 34-64 are called real-time signals, and driver programming is related to hardware.
For the specific signal list, refer to the Linux signal list_baobao8505's blog-CSDN blog_linux signal list
Four elements of a signal
1. Number 2. Name 3. Event 4. Default action
The numbers are different under different operating systems but the names are the same
Action is the default action:
Term: Terminate the process
Ign: Ignore the process
Core: Terminate the process, generate a Core file
Stop: Stop the process
Cont: Continue to run the process
Note: SIGKILL and SIGSTOP signals are not allowed to be ignored and captured, and only default actions can be performed. It can't even be set to block.
After the signal is generated, there are two states
1. Pending state: Not processed
2. Delivery state: The signal is processed
Blocking Signal Sets and Pending Signal Sets
The implementation of the signal leads to a strong delay in the signal, but for the user, the time is very short and difficult to detect
The blocking signal set
adds some signals to the set, and sets shielding for them. When the x signal is shielded, and then the signal is received, the processing of the signal will be postponed (the processing occurs after the shielding is unblocked)
The pending signal set
signal is generated, and the bit describing the signal in the pending signal set is immediately flipped to 1, indicating that the signal is in a pending state. When the signal is processed the corresponding bit flips back to 0. This moment is often very short.
signal generating function
kill function
Ordinary users cannot send signals to system users, but super users can send signals to any user
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
//parent process kill child process
int main(void){
pid_t pid = -1;
pid = fork();
if(-1 == pid){
perror("fork");
return 1;
}
//child process
if(0 == pid){
while(1){
printf("child process do work...\n");
sleep(1);
}
//exit process
exit(0);
}
else
{
//parent process
sleep(3);
printf("child process is time to exit...\n");
kill(pid,15);
printf("parent process is time to over...\n");
}
return 0;
}
Here we use kill to kill the child process after sleep 3 seconds, so it will terminate after executing the do work output 3 times
Send a signal to yourself using the raise function
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
int main(void){
int i= 1;
while(1){
printf("do working %d\n",i);
if(i == 4){
//send a id 15 signal to myself
raise(SIGTERM);
}
i++;
sleep(1);
}
return 0;
}
Output result:
do working 1
do working 2
do working 3
do working 4
Terminated
Here we use raise to send a SIGTERM signal to ourselves. If kill is used, then it is
kill(getpid(), SIGTERM); here getpid() is to get the current process id
abort function
The default is to send the termination signal No. 6
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(void){
int i = 1;
while(1){
printf("do working %d\n",i);
if(4 == i){
abort();
}
i++;
sleep(1);
}
return 0;
}
Output result:
do working 1
do working 2
do working 3
do working 4
Aborted (core dumped)
Use alarm to set timeout
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
//测试alarm函数
int main(void){
unsigned int ret = 0;
//第一次设置闹钟 5秒钟之后就超时 发送对应信号
ret = alarm(5);
printf("last alarm left time is %u\n",ret);
sleep(2);
//之前没有超时的闹钟被新的设置给覆盖
ret = alarm(3);
printf("last alarm left time is %u\n",ret);
printf("press any buton continue..\n");
getchar();
return 0;
}
last alarm left time is 0
last alarm left time is 3
press any buton continue..
Alarm clock
Timing has nothing to do with the state of the process, no matter what state the process is in, the alarm will time
setitimer timer
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
int main(void){
int ret = -1;
struct itimerval tmo;
tmo.it_value.tv_sec = 3;
tmo.it_value.tv_usec = 0;
tmo.it_interval.tv_sec = 2;
tmo.it_interval.tv_usec = 0;
ret = setitimer(ITIMER_REAL, &tmo, NULL);
if(-1 == ret){
perror("setitimer");
return 1;
}
printf("press any button to continue...\n");
getchar();
return 0;
}