一、Linux下信号介绍
Linux下进行应用编程时,信号的处理必不可少。信号可以用于多进程间通信,查看当前系统支持的所有信号: kill -l
[wbyq@wbyq linux_c]$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
几个比较常用的信号:
- SIGINT 当用户按下了<Ctrl+C>时,用户终端向当前正在运行的进程发出此信号,默认动作为是终止当前进程。
- SIGQUIT 快捷键是<Ctrl+\>,和SIGINT 一样默认动作结束当前进程.
- SIGSEGV 访问非法内存产生的信号,也就是经常遇到的
段错误
- SIGALRM 定时器超时信号,比如闹钟的时间到达就会产生该信号.
- SIGIO 数据可读写信号,一般与驱动程序交互时,设备有数据可读,就会产生该信号,通知进程去读取数据。
Linux下应用层的信号与单片机裸机程序里中断类似,都可以设置处理函数.中断服务函数
。
如果进程里不想使用信号的默认处理方式,可以自己捕获信号,然后再做相关处理。
比如: 当用户按下了<Ctrl+C>时,不想立即终止进程,可能还需要做一些善后工作,那么就可以自己捕获SIGINT信号,处理了内存释放、文件关闭、等等一些退出之前的清理工作之后,再退出。
信号的捕获函数如下:
#include <signal.h>
typedef void (*sighandler_t)(int); //函数指针类型
sighandler_t signal(int signum, sighandler_t handler);
函数功能: 注册需要捕获的信号。
函数参数:
int signum 要捕获的信号。 Kill -l
sighandler_t handler :捕获到信号后,执行的函数。
二、信号捕获、发送 案例
2.1 捕获Ctrl+C的信号
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <sys/time.h>
#include <signal.h>
/*
信号处理函数
*/
void sighandler_func(int sig)
{
printf("捕获的信号:%d\n",sig);
}
int main(int argc,char **argv)
{
//注册将要捕获的信号
signal(SIGINT,sighandler_func);
while(1)
{
}
return 0;
}
2.2 捕获段错误信号
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <sys/time.h>
#include <signal.h>
#include <stdlib.h>
/*
信号处理函数
*/
void sighandler_func(int sig)
{
printf("捕获的信号:%d\n",sig);
exit(0); //结束进程
}
int main(int argc,char **argv)
{
//注册将要捕获的信号
signal(SIGSEGV,sighandler_func);
int *p;
*p=12345; //给非法内存地址赋值
while(1)
{
}
return 0;
}
2.3 通过kill命令给指定的进程发送信号
语法:
kill -s <信号名称> <进程的PID号>
kill -<信号名称> <进程的PID号>
示例:
[wbyq@wbyq linux_c]$ kill -s SIGINT 18365
[wbyq@wbyq linux_c]$ ps
PID TTY TIME CMD
7481 pts/0 00:00:02 bash
18370 pts/0 00:02:49 a.out
18371 pts/0 00:03:28 a.out
18372 pts/0 00:02:46 a.out
18373 pts/0 00:02:36 a.out
18400 pts/0 00:00:00 ps
[1] 中断 ./a.out
[wbyq@wbyq linux_c]$ kill -s 2 18370
[wbyq@wbyq linux_c]$ ps
PID TTY TIME CMD
7481 pts/0 00:00:02 bash
18371 pts/0 00:03:39 a.out
18372 pts/0 00:02:56 a.out
18373 pts/0 00:02:47 a.out
18401 pts/0 00:00:00 ps
[2] 中断 ./a.out
[wbyq@wbyq linux_c]$
[wbyq@wbyq linux_c]$ kill -2 18371
[wbyq@wbyq linux_c]$ kill -9 18372 //强制杀死指定的信号
[wbyq@wbyq linux_c]$ ps
PID TTY TIME CMD
7481 pts/0 00:00:02 bash
18373 pts/0 00:05:31 a.out
18407 pts/0 00:00:00 ps
[4]- 已杀死 ./a.out
查看当前进程的PID
查看后台运行的所有进程:
[wbyq@wbyq linux_c]$ ps //查看当前终端后台进程
PID TTY TIME CMD
7481 pts/0 00:00:02 bash
18365 pts/0 00:00:54 a.out
18370 pts/0 00:00:04 a.out
18371 pts/0 00:00:04 a.out
18372 pts/0 00:00:05 a.out
18373 pts/0 00:00:03 a.out
18374 pts/0 00:00:00 ps
[wbyq@wbyq linux_c]$ ps -aux //查看当前系统所有的进程详细信息
wbyq 18365 65.1 0.0 1844 280 pts/0 R 09:19 1:33 ./a.out
wbyq 18370 35.9 0.0 1844 280 pts/0 R 09:20 0:34 ./a.out
wbyq 18371 34.9 0.0 1844 276 pts/0 R 09:20 0:32 ./a.out
wbyq 18372 44.7 0.0 1844 276 pts/0 R 09:20 0:41 ./a.out
wbyq 18373 34.4 0.0 1844 280 pts/0 R 09:20 0:32 ./a.out
wbyq 18375 5.0 0.0 6532 1048 pts/0 R+ 09:21 0:00 ps -aux
[wbyq@wbyq linux_c]$ top //动态查看当前系统的进程详细信息
程序后台运行的方式:
[wbyq@wbyq linux_c]$ ./a.out &
2.4 通过代码给指定的进程发送信号
函数的用法与命令一样。
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);