赞
踩
#define SIGHUP 1 /* Hangup (POSIX). */ #define SIGINT 2 /* Interrupt (ANSI). */ #define SIGQUIT 3 /* Quit (POSIX). */ #define SIGILL 4 /* Illegal instruction (ANSI). */ #define SIGTRAP 5 /* Trace trap (POSIX). */ #define SIGABRT 6 /* Abort (ANSI). */ #define SIGIOT 6 /* IOT trap (4.2 BSD). */ #define SIGBUS 7 /* BUS error (4.2 BSD). */ #define SIGFPE 8 /* Floating-point exception (ANSI). */ #define SIGKILL 9 /* Kill, unblockable (POSIX). */ #define SIGUSR1 10 /* User-defined signal 1 (POSIX). */ #define SIGSEGV 11 /* Segmentation violation (ANSI). */ #define SIGUSR2 12 /* User-defined signal 2 (POSIX). */ #define SIGPIPE 13 /* Broken pipe (POSIX). */ #define SIGALRM 14 /* Alarm clock (POSIX). */ #define SIGTERM 15 /* Termination (ANSI). */ #define SIGSTKFLT 16 /* Stack fault. */ #define SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */ #define SIGCHLD 17 /* Child status has changed (POSIX). */ #define SIGCONT 18 /* Continue (POSIX). */ #define SIGSTOP 19 /* Stop, unblockable (POSIX). */ #define SIGTSTP 20 /* Keyboard stop (POSIX). */ #define SIGTTIN 21 /* Background read from tty (POSIX). */ #define SIGTTOU 22 /* Background write to tty (POSIX). */ #define SIGURG 23 /* Urgent condition on socket (4.2 BSD). */ #define SIGXCPU 24 /* CPU limit exceeded (4.2 BSD). */ #define SIGXFSZ 25 /* File size limit exceeded (4.2 BSD). */ #define SIGVTALRM 26 /* Virtual alarm clock (4.2 BSD). */ #define SIGPROF 27 /* Profiling alarm clock (4.2 BSD). */ #define SIGWINCH 28 /* Window size change (4.3 BSD, Sun). */ #define SIGPOLL SIGIO /* Pollable event occurred (System V). */ #define SIGIO 29 /* I/O now possible (4.2 BSD). */ #define SIGPWR 30 /* Power failure restart (System V). */ #define SIGSYS 31 /* Bad system call. */ #define SIGUNUSED 31
上面提到的信号全为不可靠信号(1~31) , 这些信号全是系统内置的,这些信号已经有了预定义值,每个信号有了确定的用途、含义以及对应的名字,并且每种信号都有各自的系统默认操作(SIGUSR1和SIGUSR2除外)
hxd@ubuntu:~/learn/6.信号$ 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
当用户在终端按下中断字符(通常是 CTRL + C)时,内核将发送 SIGINT 信号给前台进程组中的每一个进程。该信号的系统默认操作是终止进程的运行。所以通常我们都会使用 CTRL + C 来终止一个占用前台的进程,原因在于大部分的进程会将该信号交给系统去处理,从而执行该信号的系统默认操作。
当用户在终端按下退出字符(通常是 CTRL + \)时,内核将发送 SIGQUIT 信号给前台进程组中的每一个进程。该信号的系统默认操作是终止进程的运行、并生成可用于调试的核心转储文件。进程如果陷入无限循环、或不再响应时,使用 SIGQUIT 信号就很合适。所以对于一个前台进程,既可以在终端按下中断字符CTRL + C、也可以按下退出字符 CTRL + \来终止,当然前提条件是,此进程会将 SIGINT 信号或 SIGQUIT信号交给系统处理(也就是没有将信号忽略或捕获),进入执行该信号所对应的系统默认操作。
当进程调用 abort()系统调用时(进程异常终止),系统会向该进程发送 SIGABRT 信号。该信号的系统默认操作是终止进程、并生成核心转储文件。
此信号为“必杀(sure kill)”信号,用于杀死进程的终极办法,此信号无法被进程阻塞、忽略或者捕获,故而“一击必杀”,总能终止进程。使用 SIGINT 信号和 SIGQUIT 信号虽然能终止进程,但是前提条件是该进程并没有忽略或捕获这些信号,如果使用 SIGINT 或 SIGQUIT 无法终止进程,那就使用“必杀信号”SIGKILL 吧。Linux 下有一个 kill 命令,kill 命令可用于向进程发送信号,我们会使用"kill -9 xxx"命令来终止一个进程(xxx 表示进程的 pid),这里的-9 其实指的就是发送编号为 9 的信号,也就是 SIGKILL 信号。
该信号供程序员自定义使用,内核绝不会为进程产生这些信号,在我们的程序中,可以使用这些信号来互通通知事件的发生,或是进程彼此同步操作。该信号的系统默认操作是终止进程。
涉及到管道和 socket,当进程向已经关闭的管道、FIFO 或套接字写入信息时,那么系统将发送该信号给进程。该信号的系统默认操作是终止进程。
与系统调用 alarm()或 setitimer()有关,应用程序中可以调用 alarm()或 setitimer()函数来设置一个定时器,当定时器定时时间到,那么内核将会发送 SIGALRM 信号给该应用程序,关于 alarm()或 setitimer()函数的使用,后面将会进行讲解。该信号的系统默认操作是终止进程。
这是用于终止进程的标准信号,也是 kill 命令所发送的默认信号(kill xxx,xxx 表示进程 pid),有时我们会直接使用"kill -9 xxx"显式向进程发送 SIGKILL 信号来终止进程,然而这一做法通常是错误的,精心设计的应用程序应该会捕获 SIGTERM 信号、并为其绑定一个处理函数,当该进程收到 SIGTERM 信号时,会在处理函数中清除临时文件以及释放其它资源,再而退出程序。如果直接使用 SIGKILL 信号终止进程,从而跳过了 SIGTERM 信号的处理函数,通常 SIGKILL 终止进程是不友好的方式、是暴力的方式,这种方式应该作为最后手段,应首先尝试使用 SIGTERM,实在不行再使用最后手段 SIGKILL。
这是一个“必停”信号,用于停止进程(注意停止不是终止,停止只是暂停运行、进程并没有终止),应用程序无法将该信号忽略或者捕获,故而总能停止进程。
该函数是 Linux 系统下设置信号处理方式最简单的接口,可将信号的处理方式设置为捕获信号、忽略信号以及系统默认操作
#include <signal.h>
typedef void (*sig_t)(int);
sig_t signal(int signum, sig_t handler);
也是绑定信号处理函数,只不过该函数功能更多
#include <signal.h>
// act参数一班只需要配置(sa_handler或sa_sigaction)和sa_flags;
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
给指定的进程或进程组发送信号, 信号发送的基本规则是发送者进程的实际用户 ID 或有效用户 ID 必须等于接收者进程的实际用户 ID 或有效用户 ID。(超级用户除外)
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
向自身进程发送信号
#include <signal.h>
int raise(int sig); // 等价于kill(getpid(), sig)
设置一个定时器(闹钟),当定时器时间到,内核会向进程发送SIGALRM信号(每个进程只能设置一个 alarm 闹钟)
alarm 闹钟并不能循环触发,只能触发一次,若想要实现循环触发,可以在 SIGALRM 信号处理函数中再次调用 alarm()函数设置定时器
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
返回值: 如果在调用 alarm()时,之前已经为该进程设置了 alarm 闹钟还没有超时,则该闹钟的剩余值作为本次 alarm()函数调用的返回值,之前设置的闹钟则被新的替代;否则返回 0。
pause()系统调用可以使得进程暂停运行、进入休眠状态,直到进程捕获到一个信号为止,只有执行了信号处理函数并从其返回时,pause()才返回
#include <unistd.h>
int pause(void);
初始化信号集,使其不包含任何信号
#include <signal.h>
int sigemptyset(sigset_t *set);
// 信号集类型,其实就是一个数组
# define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
typedef struct
{
unsigned long int __val[_SIGSET_NWORDS];
} sigset_t;
初始化信号集,使其包含所有信号(包括所有实时信号)
#include <signal.h>
int sigfillset(sigset_t *set);
// 信号集类型,其实就是一个数组
# define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
typedef struct
{
unsigned long int __val[_SIGSET_NWORDS];
} sigset_t;
向信号集添加一个信号
#include <signal.h>
int sigaddset(sigset_t *set, int signum);
向信号集删除一个信号
#include <signal.h>
int sigdelset(sigset_t *set, int signum);
测试信号集中是否存在一个信号
#include <signal.h>
int sigismember(const sigset_t *set, int signum);
返回值:如果信号 signum 在信号集 set 中,则返回 1;如果不在信号集 set 中,则返回 0;失败则返回- 1,并设置 errno。
获取信号的描述信息
#include <string.h>
char *strsignal(int sig); // 函数会对参数 sig 进行检查,若传入的 sig 无效,则会返回"Unknown signal"信息。
该函数可配置当前进程的信号掩码
信号掩码: 内核为每一个进程维护了一个信号掩码(其实就是一个信号集),即一组信号。当进程接收到一个属于信号掩码中定义的信号时,该信号将会被阻塞、无法传递给进程进行处理,那么内核会将其阻塞,直到该信号从信号掩码中移除,内核才会把该信号传递给进程从而得到处理。
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
该函数是一个原子操作。将恢复信号掩码和 pause()挂起进程这两个动作封装成一个原子操作,这sigsuspend()函数会将参数 mask 所指向的信号集来替换进程的信号掩码。
#include <signal.h>
int sigsuspend(const sigset_t *mask);
//等价于
sigprocmask(SIG_SETMASK, &mask, &old_mask);
pause();
sigprocmask(SIG_SETMASK, &old_mask, NULL);
获取等待中的信号
#include <signal.h>
int sigpending(sigset_t *set);
发送实时信号
接收该实时信号的进程要为该信号建立一个信号处理函数,使用sigaction函数为信号建立处理函数,
并加入 SA_SIGINFO,这样信号处理函数才能够接收到实时信号以及伴随数据,也就是要使用
sa_sigaction 指针指向的处理函数,而不是 sa_handler,当然允许应用程序使用 sa_handler,但这样
就不能获取到实时信号的伴随数据了。
#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval value);
// 通过测试发现使用sival_ptr传递过去没问题,但访问就会出现段错误。仔细想想也是,一个进程是不能访问另一个进程的空间的。
typedef union sigval
{
int sival_int;
void *sival_ptr;
} sigval_t;
#include <stdlib.h>
void abort(void);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。