1, 信号介绍
介绍信号前先复习一下中断,中断的意思就是比如你在写作业,忽然有人打电话过来了,你就得去接电话,这里电话铃声就是一种信号,你去接电话的动作就是中断处理程序。
信号是软件中断,它提供了一种处理异步事件的方法。每个信号都有一个名字,这些名字都是以SIG开头。 使用命令kill -l 可以查看当前系统支持的信号。
信号值位于SIGRTMIN和SIGRTMAX之间的信号都是可靠信号,可靠信号克服了信号可能丢失的问题。
- 下面是常用的信号
信号编号 | 信号名 | 信号说明 | 默认动作 |
---|---|---|---|
2 | SIGINT | Ctrl+C按键终止程序运行的信号 | 程序终止 |
4 | SIGILL | 非法的指令 | 程序终止 |
7 | SIGBUS | 运行非本CPU相关编译器编译的程序 | 程序终止 |
9 | SIGKILL | 强制杀死程序信号,任何程序都不可以捕捉该信号 | 程序终止,不可被捕捉 |
10 | SIGUSR1 | 用户自定义信号1 | 程序终止 |
11 | SIGSEGV | 段错误系统给程序发送的信号 | 程序终止 |
12 | SIGUSR2 | 用户自定义信号2 | 程序终止 |
13 | SIGPIPE | 管道破裂信号 | 程序终止 |
14 | SIGALRM | alarm()系统调用发送的信号 | 程序终止 |
15 | SIGTERM | kill命令默认发送的信号,默认动作是终止信号 | 程序终止 |
17 | SIGCHLD | 子进程退出信号 | 忽略该信号 |
编号为0的信号有特殊用途,我们可以给某个进程发0号信号来判断该进程是否正在运行。在某个信号发生时,可以告诉内核按照下面三种方式进行处理:
1, 忽略此信号 //还是上面的例子,当听到手机铃声响起的时候,你可以选择忽略这个声音,假装没听见继续写作业
2,捕捉此信号 //当然你也可以选择接听这个电话1
3,执行系统默认动作。//比如你妈妈在早上出门前就跟你说下午打电话给你就代表她回家了,你不用接电话,而是去开门就行
kill 命令默认发 SIGTERM信号,如果SIGTERM被捕捉后,那么kill命令就不能停止该进程运行,
这时需要使用kill -9(SIGKILL)可以强制杀死某个进程。
- 上面例子中我们创建了ping进程,首先我们按 ctrl+z,这是给进程发送了挂起的信号,我们发现当我们ps后,这个信号是杀不死这个进程的。
- 后面我们kill 3219, 这其实只是发送了信号编号为15的默认信号 SIGTERM, 我么发现同样杀不死ping这个进程
- 最后我们加了9号信号SIGKILL,因为这个信号是不可被捕捉的,最后成功杀死这个进程。
另外我们看看下面的例子进一步了解信号的概念
- 上面我们按了 CTRL+c,ps 后发现ping命令被成功杀死,这里其实给进程发送了编号为2的SIGINT信号
2, 安装信号
信号是进程间通信机制中唯一的异步通信机制
signal()和sigaction()为信号安装函数
这两个函数的最大区别在于,经过sigaction安装的信号都能传递信息给信号处理函数,而经过signal安装的信号不能向信号处理函数传递信息。
简单说就是sigaction()比 signal()更加安全,信号不会丢失。所以我们一般使用sigaction(),而且它的功能更多。
- 下面是两个函数的原型
signal()
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
//第一个参数是信号的编号,第二个是收到信后后需要执行的函数名称
下面是signal()函数的简单例子
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void sig_handl(int signum)
{
printf("catch siganl [%d]\n",signum); //打印收到信号的编号
}
int main(int argc, char *argv[])
{
signal(SIGINT, sig_handl); //这里表示给程序安装了2号信号,即当按(ctrl+c)时程序就会去执行sig_handl函数里的内容
while (1)
{
;
}
return 0;
}
- 因为程序安装了信号SIG_INT后执行sig_handl()函数,所以当我们按下ctrl +c 后并不能像之前杀死ping进程那样杀死进程了。
sigaction()
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
参数:
signum:信号值
act:信号的处理参数
oldact:保存信号上次安装时的处理参数(备份的作用)
返回值:0(success),-1(error)
- 下面是结构体
struct sigaction {
void (*sa_handler)(int); //信号处理函数
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask; //信号屏蔽集
int sa_flags;
void (*sa_restorer)(void);// 已废弃
};
- 下面给出和上面signal()相同功能的等价程序
void sig_handl(int signum)
{
printf("catch siganl [%d]\n",signum);
}
int main(int argc, char *argv[])
{
struct sigaction sigact; //定义结构体
//下面三条语句初始化结构体
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigact.sa_handler = sig_handl;
sigaction(SIGINT, &sigact, 0); //安装信号
while (1)
{
;
}
return 0;
}