信号是软中断,它提供了一种处理异步事件的方法。在linux系统中,每个信号都有一个名字,这些名字都已sig开头,通过kill -l命令可以查看所有信号。
注意上图:
本文内容仅限于前31个普通信号,且仅讨论用的相对较多的部分信号。
信号的产生有多种方式:
信号的处理一般有三种方式:
有两个信号比较特殊:sigkill和sigstop,它们既不能被忽略,也不能被捕捉。
注意:
信号 | 产生条件及功能说明 | 系统默认动作 |
---|---|---|
sigabrt | 调用abort() | 进程终止 + coredump |
sigalrm | alarm或settimer超时 | 进程终止 |
sigchld | 子进程终止时,发送该信号给父进程 | 忽略 |
sigfpe | 算术运行异常,如除0、浮点溢出等 | 进程终止 + coredump |
sigint | 命令行终端按ctrl+c时,发送该信号给所有的前台进程,常用于终止运行失控的进程 | 进程终止 |
sigquit | 命令行终端按ctrl+\时,发送该信号给所有的前台进程,作用和sigint相同,但会产生cordump文件 | 进程终止 + coredump |
sigtstp | 命令行终端按ctrl+z时,发送该信号给所有的前台进程,用于停止进程 | 停止进程 |
sigio | 指示一个异步io事件 | 进程终止/忽略 |
sigkill | 不能被捕捉和忽略,只能采取系统默认动作 | 进程终止 |
sigstop | 不能被捕捉和忽略,只能采取系统默认动作 | 进程终止 |
sigterm | 由kill函数或kill命令产生,发送给应用程序捕获,reboot命令就用到了该信号 | 进程终止 |
sigsegv | 无效内存引用,段错误 | 进程终止 + coredump |
sigusr1 | 用户自定义信号,可用于应用程序 | 进程终止 |
sigusr2 | 用户自定义信号,可用于应用程序 | 进程终止 |
signal函数用于给某个信号指定信号处理方式。
#include <signal.h> typedef void (*sighandler_t)(int); //成功返回旧的信号处理函数,失败返回sig_err sighandler_t signal(int signum, sighandler_t handler);
参数说明:
信号集sigset_t是一种能表示多个信号的数据类型,signal.h提供了下列5个处理信号集的函数。
#include <signal.h> //4个函数返回值:成功返回0,失败返回-1 int sigemptyset(sigset_t *set); //初始化由set指向的信号集,清除其中所有信号 int sigfillset(sigset_t *set); //初始化由set指向的信号集,使其包含所有信号 int sigaddset(sigset_t *set, int signum); //将一个信号signum添加到信号集set中 int sigdelset(sigset_t *set, int signum); //将一个信号signum从信号集set中删除 //若信号signum在信号集set中,则返回1,否则返回0 int sigismember(const sigset_t *set, int signum); //判断信号signum是否在信号集set中
应用程序在使用信号集前,必须要先对该信号集调用一次sigemptyset或sigfillset,之后就可以调用sigaddset或sigdelset在该信号集中增删特定的信号。
#include <signal.h> //成功返回0,失败返回-1 int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
参数说明:
参数how | 说 明 |
---|---|
sig_block | 新的信号屏蔽字是其当前信号屏蔽字和set指向信号集的并集,set包含了希望阻塞的附加信号 |
sig_unblock | 新的信号屏蔽字是当前信号屏蔽字和set指向信号集补集的交集,set包含了希望解除阻塞的信号 |
sig_setmask | 新的信号屏蔽字是set指向的信号集 |
sigaction用于获取某个信号的现有handler,或者为其设置新的handler,或者二者都有,它改善了signal要想获得当前handler,必须先设置新的handler的缺陷。
apue推荐用sigaction代替signal,但这个函数用起来比signal麻烦的多,目前实际工程中还是以使用signal居多。
#include <signal.h> struct sigaction { void (*sa_handler)(int); void (*sa_sigaction)(int, siginfo_t *, void *); sigset_t sa_mask; int sa_flags; void (*sa_restorer)(void); }; //成功返回0,失败返回-1 int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
参数说明:
当act不为null时:
kill函数将信号发送给进程或进程组,raise函数用于进程向自身发送信号。
#include <signal.h> //成功返回0,失败返回-1 int kill(pid_t pid, int signum); int raise(int signum); //raise(signum) <==> kill(getpid(), signum)
kill的pid参数有以下4种不同的情况:
使用alarm可以设置一个定时器(闹钟时间),当定时器超时时,会产生sigalrm信号,如果应用程序忽略或不捕捉该信号,则会采用系统默认动作——终止调用alarm的进程。
#include <unistd.h> //返回值:0或者以前设置的定时器剩余秒数 unsigned int alarm(unsigned int seconds);
pause函数使调用进程阻塞直到捕捉到一个信号。
#include <unistd.h> //返回-1,errno设置为eintr int pause(void);
只有执行了一个信号处理函数并从其返回时,pause才返回,在这种情况下,pause返回-1,errno设置为eintr。
信号可重入函数是指在信号处理程序中保证调用安全的函数,也叫做异步信号安全函数,下图列出了所有的信号可重入函数,其中所有的系统调用都是信号可重入函数。
没有列入上图的大多数函数是信号不可重入函数,主要原因有:
应用程序使用信号的步骤其实很简单:
应用程序使用信号的步骤其实也很复杂:
如对本文有疑问, 点击进行留言回复!!
linux下文本编辑器vim的使用方法(复制、粘贴、替换、行号、撤销、多文件操作)
网友评论