目录
类别 | 描述 |
---|---|
信号的定义 | 信号是事件发生时对进程的通知机制,可以理解为软件中断,通常用于处理异步事件。 |
信号与硬件中断的相似性 | 信号与硬件中断相似,能够打断程序的正常流程,通知进程处理特定的事件。 |
信号的作用 | 用于进程间通信(IPC)和同步。信号通过通知进程某些事件的发生,进而影响进程的行为。 |
信号产生的条件
条件 | 说明 |
---|---|
硬件异常 | 例如除数为 0、访问非法内存等,硬件检测到异常后由内核向进程发送信号。 |
终端输入 | 用户通过按键(如 CTRL + C、CTRL + Z 等)触发的信号。 |
进程调用 kill() |
进程可以使用 kill() 系统调用向另一个进程发送信号,前提是进程具有合适的权限。 |
用户使用 kill 命令 |
用户在终端使用 kill 命令发送信号给其他进程,例如使用 kill -9 <pid> 来终止进程。 |
软件事件 | 进程执行过程中,系统检测到某些事件发生时(如定时器超时、CPU 时间限制等),内核向进程发送信号。 |
信号的处理方式
处理方式 | 说明 |
---|---|
忽略信号 | 进程选择忽略某些信号。大多数信号可以被忽略,但 SIGKILL 和 SIGSTOP 不能被忽略。忽略某些硬件异常信号会导致未定义的行为。 |
捕获信号 | 进程注册一个自定义的信号处理函数,在信号到达时,内核会调用该函数处理信号。可以使用 signal() 系统调用来注册信号处理函数。 |
执行系统默认操作 | 当进程不处理信号时,系统会执行该信号的默认操作。大多数信号的默认操作是终止进程,除非是 SIGKILL 或 SIGSTOP 。 |
信号的异步性质
特性 | 说明 |
---|---|
异步事件 | 信号是异步事件,进程无法预测信号的确切时间,信号的到来是随机的,类似于硬件中断。进程无法通过简单的变量测试或系统调用判断是否会发生信号,只有当信号到达时,才会中断当前进程的执行。 |
/* Signals. */
#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). */
信号名称 | 说明 | 默认操作 |
---|---|---|
SIGINT | 当用户按下 CTRL + C 时,内核将发送该信号给前台进程组中的进程。 | 终止进程 |
SIGQUIT | 当用户按下 CTRL + \ 时,内核将发送该信号给前台进程组中的进程。 | 终止进程并生成核心转储文件 |
SIGILL | 进程执行非法的机器指令时,内核发送该信号。 | 终止进程 |
SIGABRT | 当进程调用 abort() 系统调用时,发送该信号。 |
终止进程并生成核心转储文件 |
SIGBUS | 进程发生总线错误(内存访问错误)时,内核发送该信号。 | 终止进程 |
SIGFPE | 进程发生算术错误时(如除零),内核发送该信号。 | 终止进程 |
SIGKILL | 进程无法阻塞、忽略或捕获该信号。用于强制终止进程。 | 终止进程 |
SIGUSR1 | 用户自定义信号,通常用于进程间通信或同步。 | 终止进程 |
SIGSEGV | 进程对无效内存引用时,内核发送该信号。 | 终止进程 |
SIGUSR2 | 用户自定义信号,通常与 SIGUSR1 一样使用。 | 终止进程 |
SIGPIPE | 当进程向已关闭的管道、FIFO 或套接字写入时,内核发送该信号。 | 终止进程 |
SIGALRM | 当定时器到期时,内核通过 alarm() 或 setitimer() 系统调用发送该信号。 |
终止进程 |
SIGTERM | 默认终止进程的信号,也常通过 kill 命令发送。 |
终止进程(进程可捕获并清理资源) |
SIGCHLD | 当子进程终止或状态发生变化时,内核发送该信号给父进程。 | 忽略信号 |
SIGCLD | 同 SIGCHLD ,是同义词。 |
忽略信号 |
SIGCONT | 发送给停止状态的进程,恢复其运行。 | 恢复进程运行(如果进程处于停止状态) |
SIGSTOP | 强制停止进程,无法被忽略或捕获。 | 停止进程 |
SIGTSTP | 当用户按下 CTRL + Z 时,内核将发送该信号使进程停止。 | 停止进程 |
SIGXCPU | 当进程的 CPU 时间超出资源限制时,内核发送该信号。 | 终止进程 |
SIGVTALRM | 应用程序通过 setitimer() 设置虚拟定时器时,定时器到期时发送该信号。 |
终止进程 |
SIGWINCH | 当终端窗口尺寸发生变化时(例如用户调整大小或应用程序调用 ioctl() 设置),内核发送该信号。 |
终止进程 |
SIGPOLL/SIGIO | 当异步 I/O 事件发生时,内核发送该信号。 | 终止进程 |
SIGSYS | 当进程发起的系统调用错误时,内核发送该信号。 | 终止进程 |
信号的一些常见的操作
signal()
原型:
void (*signal(int signum, void (*handler)(int)))(int);
说明:
-
signal()
用于指定一个信号的处理函数,当信号到达时,操作系统会调用该处理函数。 -
第一个参数
signum
是需要处理的信号的编号(如SIGINT
,SIGTERM
等)。 -
第二个参数handler是信号处理函数的指针,用户可以自定义该函数以处理特定信号。
-
如果
handler
为SIG_IGN
,表示忽略该信号。 -
如果
handler
为SIG_DFL
,表示恢复默认的信号处理行为。
-
-
返回值是之前信号处理函数的地址,可以用来恢复原始信号处理。
注意:
-
signal()
是一个相对简化的接口,不适合处理复杂的信号处理需求,且其行为在不同的系统中可能有所不同。 -
在现代系统中,推荐使用
sigaction()
替代signal()
,因为sigaction()
提供了更多的控制选项。
sigaction()
原型:
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
说明:
-
sigaction()
用于更精细地控制信号的处理。它允许用户指定信号处理程序、处理程序的行为、以及如何恢复原来的信号处理行为。 -
第一个参数
signum
是信号编号。 -
第二个参数act是一个指向struct sigaction的指针,该结构体定义了信号处理程序的详细信息。
-
sa_handler
:信号处理函数的指针。 -
sa_mask
:一个信号集,表示在信号处理程序执行期间要阻塞的信号。 -
sa_flags
:指定信号处理程序的行为。常见的标志包括SA_RESTART
(使得系统调用在被信号打断后自动重启)和SA_SIGINFO
(启用额外的信号信息传递)。
-
-
第三个参数
oldact
是一个指向struct sigaction
的指针,用于保存原来的信号处理设置,以便稍后恢复。
返回值:
- 成功时返回
0
,失败时返回-1
,并设置errno
。
raise()
原型:
int raise(int signum);
说明:
-
raise()
用于向当前进程发送一个信号。它将信号发送到当前进程的进程组中。 -
参数
signum
是要发送的信号编号。 -
返回值:成功时返回
0
,失败时返回-1
,并设置errno
。
kill()
原型:
int kill(pid_t pid, int signum);
说明:
-
kill()
用于向指定进程或进程组发送信号。即使是向自己的进程发送信号,它也能有效地触发信号的处理。 -
参数pid是目标进程的 PID:
-
如果
pid > 0
,发送信号给指定的进程。 -
如果
pid == 0
,发送信号给与当前进程属于同一进程组的所有进程。 -
如果
pid == -1
,发送信号给所有进程(需要超级用户权限)。 -
如果
pid < -1
,发送信号给指定进程组的所有进程。
-
-
参数
signum
是信号编号(如SIGINT
,SIGTERM
等)。 -
返回值:成功时返回
0
,失败时返回-1
,并设置errno
。
sigprocmask()
原型:
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
说明:
-
sigprocmask()
用于控制进程的信号屏蔽字,屏蔽字表示进程在处理信号时哪些信号应被暂时阻塞。 -
参数how定义了操作方式:
-
SIG_BLOCK
:将信号集中的信号加入到当前的信号屏蔽字中。 -
SIG_UNBLOCK
:从当前屏蔽字中删除信号集中的信号。 -
SIG_SETMASK
:将信号集设置为指定的信号集。
-
-
参数
set
是一个信号集,包含要屏蔽或解除屏蔽的信号。 -
参数
oldset
用于保存操作前的信号屏蔽字。
sigpending()
原型:
int sigpending(sigset_t *set);
说明:
-
sigpending()
用于检查当前进程是否有被屏蔽但尚未处理的信号。 -
参数
set
是一个信号集,函数会将所有挂起的信号保存到该信号集。 -
返回值:成功时返回
0
,失败时返回-1
,并设置errno
。
sigwait()
原型:
int sigwait(const sigset_t *set, int *signo);
说明:
-
sigwait()
用于同步地等待一个指定信号集中的信号到达,并阻塞直到接收到该信号。 -
参数
set
是一个信号集,指定了进程要等待的信号。 -
参数
signo
用于返回接收到的信号编号。 -
返回值:返回
0
表示成功,返回-1
表示错误,errno
设置为相应的错误码。