资讯动态

Linux 学习笔记(二十九):进程信号(上)—— 信号捕捉与异步魔法

发布时间:2026/10/26 18:21:15 来源:尧图企业网站定制
一、 什么是进程信号信号Signal是 Linux 操作系统中用于进程间异步通知的一种机制属于软中断。就像快递员给你送快递你不需要一直在门口等着快递到了会打电话通知你。进程收到信号后有三种处理方式默认动作SIG_DFL系统预设的操作如 CtrlC 就是默认终止。忽略SIG_IGN收到后当作没看见。自定义捕捉执行程序员指定的自定义函数。二、 信号的产生方式终端按键如CtrlC(SIGINT, 2号)、Ctrl\(SIGQUIT, 3号)、CtrlZ(SIGTSTP, 20号)。系统调用kill(pid, sig)给指定进程发信号。raise(sig)给自己发信号。abort()给自己发 SIGABRT 信号异常终止。软件条件alarm(seconds)。调用后设置一个定时器时间一到内核给该进程发送 SIGALRM (14号) 信号。硬件异常除零错误 (SIGFPE, 8号)、非法内存访问/野指针 (SIGSEGV, 11号)。三、 实战自定义信号捕捉使用signal(int signum, handler)函数可以改变信号的处理动作。void my_handler(int signo) { printf(捕捉到信号: %d\n, signo); } int main() { signal(SIGINT, my_handler); // 拦截 CtrlC while(1) { printf(我在死循环里等信号...\n); sleep(1); } }在这个实战中进程对CtrlC产生了免疫。如果真的要退出需要发送 9号信号 (SIGKILL)这是一种绝对无法被捕捉和忽略的终极杀招。四、pause()的妙用pause()函数会让当前进程进入无 CPU 消耗的挂起状态S状态直到进程收到一个由信号捕捉函数处理并返回的信号为止。非常适合用来做基于信号驱动的异步程序。总结信号是操作系统的神经系统。理解信号的自定义捕捉是编写健壮的服务端程序如处理优雅退出的必备基自我实战操作咱们建个新目录来玩信号。cd ~/linux_study mkdir signal_test cd signal_test实战 1让进程“刀枪不入”wvim sig_catch.c(输入以下代码)#include stdio.h #include unistd.h #include signal.h // 自定义信号处理函数 void my_handler(int signo) { printf(\n[捕捉到信号] 编号: %d, 我是不会退出的\n, signo); } int main() { // 注册捕捉函数收到 2号信号(SIGINT, 即CtrlC) 时执行 my_handler // 如果写 signal(SIGINT, SIG_IGN); 就是忽略该信号 signal(SIGINT, my_handler); while(1) { printf(我在死循环里等信号...\n); sleep(1); } return 0; }编译并运行bashgcc sig_catch.c -o sig_catch ./sig_catch现象你在终端里猛按CtrlC它不但不会死还会打印出你自定义的提示语怎么退出因为CtrlC被我们拦截了你得按Ctrl\发送3号信号SIGQUIT或者新开一个终端用kill -9 进程PID杀掉它。实战 2体验系统调用kill和raise以及alarmvim sig_alarm.c(输入以下代码)#include stdio.h #include unistd.h #include signal.h #include stdlib.h void handler_alarm(int signo) { printf(闹钟响了收到信号: %d\n, signo); exit(0); } int main() { signal(SIGALRM, handler_alarm); // 捕捉闹钟信号 alarm(3); // 3秒后触发 SIGALRM printf(我给自己设了个3秒的闹钟自己给自己发信号...\n); while(1) { pause(); // 将进程挂起直到收到信号 } return 0; }编译运行gcc sig_alarm.c -o sig_alarm ./sig_alarm现象程序卡住 3 秒然后打印“闹钟响了”接着退出。pause()是个非常牛的函数它会让进程进入睡眠状态一点 CPU 都不占直到被信号“叫醒”。实战 3模拟野指针崩溃信号vim sig_segv.c(输入以下代码)#include stdio.h #include signal.h void handler(int signo) { printf(抓到了信号编号: %d (段错误)\n, signo); } int main() { signal(SIGSEGV, handler); // 捕捉段错误信号 (11号) int *p NULL; *p 100; // 故意触发野指针访问异常OS会发 SIGSEGV return 0; }(编译运行你会发现原本要直接崩溃的程序打印出了“抓到了”但是它依然会崩溃。因为硬件异常哪怕你捕捉了返回时还是会在那条非法指令处再次触发异常形成死循环OS最终还是会把它杀掉。这也是段错误很难“捕捉”着救回来的原因。)

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑