在Linux中,signal是一种局限较强的进程间通信方式。
主要有三种类型:
1. 从hardware signal到POSIX signal
hardware signal也叫hardware interrupt,CPU中存放着 interrupt vectors 指向 存放在kernel space中的interrupt handling routine。
例: 键盘输入;segmentation fault -> SIGSEGV
2. 直接从kernel生成的POSIX signal
例:exit() -> SIGCHLD
3. 从一个进程发起到另一个进程的signal
例:进程885 执行了 “kill 1234” 代码
POSIX signal
1. Generated from CPU to kernel, or from CPU to processes
例 1: Segmentation fault.
The signal is labeled SIGSEGV, which comes from CPU to kernel then to process.
例 2: Floating point exception (e.g., divided by 0).
The signal is labeled SIGFPE, which is coming from CPU to process
2. From kernel to process
例: Child process termination.
The signal is labeled SIGCHLD, which is coming from the kernel to process
3. Generated from one process to another
例: From terminals: E.g., “Ctrl C”, “Ctrl Z”
Using programs: E.g., “kill”, “top”, etc.
Using the “kill()” system call.
一些典型的signal
Asynchronous signal: 异步信号
– The signal received is NOT generated by the process itself。 So, its arrival time is usually not deterministic
– E.g., External hardware interrupt, another process sends ctrl-c
Synchronous signal: 同步信号
– The signal is caused by the process itself, its arrival time is usually deterministic
– E.g., A certain line leads to SIGFPE
– E.g., A certain line accesses a memory region: SIGSEGV
kill() 方法
用于给特地进程发送POSIX signal
signal() 方法
更新当前进程的特定signal的处理方法,即signal handler
例:写个无法“Ctrl+C”中止的小病毒
#include <stdio.h>
#include <signal.h>
void sig_handler(int sig) {
if(sig == SIGINT)
printf("\nCtrl + C\n");
}
int main(void) {
signal(SIGINT, sig_handler);
printf("Press enter\n");
getchar();
printf("End of program\n");
return 0;
}
通常情况下,我们希望当signal handler处理完signal后,程序恢复到之前执行的地方;而有时候,则希望程序继续运行下去。
signal的检查方法
一个进程如何知道它收到了一个特定的signal?
在kernel space中,有一个bitmask
进程会不定期地去检查这个bitmask,如果看到是1,则调用对应的handler,并重置为0。
因此,发送signal和处理signal是异步的。
pause()方法
The pause() system call suspends the calling process until a signal is received. 等待一个信号
有益的重写signal handler
重写SIGINT的handler,保证进程在被用户ctrl-c 中止之前,进行一些必要的清理工作比如 关闭数据库连接等。
alarm()方法
设置一个“闹钟”在指定时间后“响”起。
通过在hardware设置一个闹钟,到达时间后,hardware的signal会转换成SIGALRM signal发送给进程,默认的处理方式是结束当前进程。
alarm()是一次性的,如果需要周期性的,则使用 settimer()方法