【Linux】详解用户态和内核态&&内核中信号被处理的时机&&sigaction信号自定义处理方法
在Linux操作系统中,CPU有两种基本模式:内核模式(Kernel Mode)和用户模式(User Mode)。当CPU在内核模式下运行时,它可以执行指令集中的任何指令,并且可以访问所有内存和所有外围设备。当CPU在用户模式下运行时,它只能执行指令集中的一个子集,称为用户空间指令集(User Space Instruction Set),并且只能访问为用户空间分配的内存区域。
当一个任务(进程)在执行用户空间的代码时,它处于用户态;而当它执行内核空间的代码时,它处于内核态。内核态通常用于执行如下操作:
- 设备管理
- 进程管理
- 内存管理
在用户态下,进程不能直接执行这些操作,因为这会涉及到系统资源,通常需要通过系统调用来间接执行。
在Linux系统中,信号(signal)是一种异步事件,用来通知进程发生了某些事情。当内核检测到一个信号事件发生时,会将信号放入进程的信号队列中。当进程执行到安全点(safe point)时,即将离开用户空间进入内核空间时,内核会检查是否有信号需要处理,并执行信号的默认处理动作或者执行用户自定义的处理函数。
sigaction
函数用于改变进程的信号处理行为。它可以用来设定当信号被触发时应该采取的行动。函数原型如下:
#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
其中 signum
是要处理的信号编号,act
是指向 sigaction
结构体的指针,该结构体定义了对指定信号的处理行为,包括信号处理函数和其他选项。oldact
也是一个 sigaction
结构体的指针,用于保存原来对应信号的处理行为。
以下是使用 sigaction
函数设置自定义信号处理函数的例子:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void sig_handler(int signum) {
printf("Caught signal %d\n", signum);
// 处理信号...
}
int main() {
struct sigaction sa;
sa.sa_handler = &sig_handler; // 指定信号处理函数
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask); // 初始化信号屏蔽字
if (sigaction(SIGINT, &sa, NULL) == -1) {
printf("Failed to set signal handler for SIGINT\n");
return -1;
}
while(1) {
pause(); // 暂停进程,等待信号
}
return 0;
}
在这个例子中,程序设置了 SIGINT
(通常由Ctrl+C产生)的处理函数 sig_handler
。当用户输入Ctrl+C时,会触发 SIGINT
信号,进程会暂停,并在收到信号后恢复,调用 sig_handler
函数处理信号。
评论已关闭