前言
本篇文章我们来讲解信号的处理机制,信号处理在Linux操作系统中必不可少,这一点值得大家注意,信号又会与中断,异常一起讨论,那么下面我们就来看看到底什么是信号吧。
一、中断,异常,信号的区别
中断、异常和信号是计算机系统中的三个相关但不完全相同的概念。它们在发生的时机、触发方式和处理机制上有所不同。
中断(Interrupt):
1.中断是由硬件发出的一种信号,用于打断处理器当前的执行流程,以响应特定的硬件事件或请求。
2.中断可以来自外部设备(例如键盘、鼠标、硬盘控制器)或系统内部(例如定时器、异常或错误)。
3.当发生中断时,处理器会暂停当前的执行并切换到中断处理程序来处理中断事件,然后在处理完中断后回到原来的执行上下文。
异常(Exception):
1.异常是在程序执行期间发生的事件或错误条件,可能导致程序的正常流程中断。
2.异常可以是由硬件错误(例如除零错误、无效的内存访问)或软件错误(例如逻辑错误、非法操作)触发的错误情况。
3.异常通常是同步的,也就是说,它们在执行特定的指令时发生,并由程序自身或相关硬件直接处理。
4.异常的处理方式通常由编程语言、操作系统或硬件定义,可以通过异常处理机制(例如 try-catch 块)捕获和处理。
信号(Signal):
1.信号是一种在软件层面上由操作系统或进程间通信机制发送的异步通知。
2.信号可以用于通知进程发生的特定事件,如用户操作(例如按下 Ctrl+C),操作系统事件(例如进程终止),或由其他进程发送的消息。
3.信号是在进程执行期间以异步方式发出的,可以打断当前的执行流程。
4.信号通常用于处理外部事件或异常情况,例如捕获异常,终止进程或重新启动进程等。
总结:
1.中断是由硬件发出的打断处理器当前执行流程的信号,用于响应硬件事件。
2.异常是在程序执行期间发生的事件或错误条件,用于响应特定的错误情况。
3.信号是在软件层面上由操作系统或进程间通信机制发送的异步通知,用于处理外部事件或异常情况。
它们在触发方式、处理机制和使用场景上有所不同,但都可以用于在计算机系统中处理特定的事件、错误和异常情况。
二、信号在Linux中的标识
每个信号都由一个唯一的数字标识符来表示,这些数字被称为信号编号。
信号编号是整数值,通常用正整数来表示,例如SIGINT、SIGTERM等。这些信号编号定义在系统头文件 <signal.h> 中,并在C语言中使用 SIG 前缀。
以下是一些常见的信号编号及其含义:
SIGHUP (1): 终端挂起或控制进程终止。
SIGINT (2): 使用键盘输入的中断信号。
SIGQUIT (3): 使用键盘输入的退出信号。
SIGILL (4): 非法指令。
SIGABRT (6): 异常终止。
SIGFPE (8): 浮点异常。
SIGKILL (9): 强制进程终止。
SIGALRM (14): 闹钟超时。
SIGTERM (15): 终止请求。
三、信号处理相关函数
signal()
函数原型:
void (*signal(int signum, void (*handler)(int)))(int)
功能:signal() 函数用于注册信号处理函数,指定在接收到特定信号时要执行的操作。
参数:
signum:要捕获和处理的信号编号。
handler:指向信号处理函数的指针,可以是自定义函数或内置的信号处理函数。
返回值:返回一个函数指针,指向以前注册的信号处理函数。
raise()
函数原型:
int raise(int sig)
功能:raise() 函数用于在当前进程内部生成信号。它向当前进程发送指定的信号。
参数:
sig:要发送的信号编号。
返回值:成功时返回0,否则返回一个非零值。
kill()
函数原型:
int kill(pid_t pid, int sig)
功能:kill() 函数用于向指定进程或进程组发送信号。
参数:
pid:要发送信号的进程的进程ID(PID)。可以是正整数值,表示单个进程的PID,也可以是负整数值,表示进程组的PID(将信号发送给该进程组中的所有进程)。
sig:要发送的信号编号。
返回值:成功时返回0,否则返回一个非零值。
这些函数可以一起使用来进行信号的处理。首先,使用 signal() 函数注册信号处理函数,指定接收到特定信号时要执行的操作。然后,可以使用 raise() 函数在当前进程中生成信号,或使用 kill() 函数向其他进程发送信号。
需要注意的是,不同的信号有不同的含义和用途。要正确使用信号处理函数和相关函数,需要了解不同的信号及其处理方式。可以通过查阅相关文档或系统头文件 <signal.h> 了解所有可用的信号及其意义。
四、代码实验
#include <signal.h> #include <stdio.h> #include <unistd.h> void signal_handle(int sig) { printf("sig = %d\n", sig); } int main(void) { signal(SIGINT, signal_handle); while(1) { sleep(1); } return 0; }
执行效果:
按下ctrl加c后被信号处理函数捕捉到了,并且打印了信号的数值。
下面的代码演示了怎么样使用信号进行线程之间通信。
#include <signal.h> #include <stdio.h> #include <unistd.h> void signal_handle(int sig) { printf("sig = %d\n", sig); } int main(void) { signal(40, signal_handle); while(1) { sleep(1); } return 0; }
#include <signal.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <stdlib.h> int main(int argc, char** argv) { pid_t pid = atoi(argv[1]); kill(pid, 40); raise(SIGINT); while(1) { sleep(1); } return 0; }
总结
本篇文章就讲解到这里,大家看完后可以好好实验一下。