1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | /************************************************************************* > File Name: signal.c > Author: > Mail: > Created Time: 2015年11月21日 星期六 10时21分58秒 ************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> void sig_handler( int num){ if (num == SIGINT){ printf ( "receive the SIGINT: %d\n" , num); } else if (num == SIGQUIT){ printf ( "recevie the SIGQUIT: %d\n" , num); } } int main() { signal (SIGINT, sig_handler); signal (SIGQUIT, sig_handler); printf ( "enter to the while.\n" ); while (1){ sleep(1); } exit (0); } |
按下Ctrl+c发出中断信号,也就是发出SIGINT信号;按下Ctirl+\发出退出信号,也就是发出SIGQUIT信号;
signal函数是让程序捕获到设置的信号(第一个参数指定)的时候,去执行设置的信号处理函数(第二个参数指定);
运行结果如下:
如果想退出程序,按下Ctrl+z强制退出,但是此时输入ps,可以看到刚才运行的程序没有真正退出,这时候我们要杀死该进程;
输入:kill -9 进程号 然后再ps查看,可以看到刚才的进程已经被杀死;
实例二:
在进程控制块里面有一个64bit(0-63)的数据块,表明信号的屏蔽状态,也就是信号屏蔽状态字;每个bit表明一个信号的屏蔽状态,
比如bit1如果是1,表明SIGINT信号是被阻塞的,也就是进程收到SIGINT信号之后不会去执行,而是将该信号阻塞起来,当该信号设置为
非阻塞的时候才会去处理该SIGINT信号;
那么我们怎么设置这64个信号的阻塞和非阻塞的状态呢???内核提供了API函数,
第一步:定义sigset_t的一个变量set;
第二步:将该变量的值清零,sigemptyset(&set);
第三步:将要设置的信号添加到该信号集合中,也就是set变量中;比如:sigaddset(&set,SIGINT);
第四步:将该信号集合set注册到该进程的控制块的信号屏蔽状态字中;
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);向内核里面设置信号集set;
当how是SIG_BOLCK的时候,设置该信号为阻塞;是SIG_UNBLOCK的时候,设置该信号为非阻塞;
set是刚才自定义的信号集合,oset可以返回进程控制块中的以前的信号屏蔽字的状态;(如果不需要,则设为NULL)
在进程控制块里面还有一个信号未决状态字,也是64bit,用来指明该64个信号;比如:bit1被置为了1,表明收到了SIGINT信号,但是
该信号被阻塞,没有被处理;如果bit1被置为了0,表明SIGINT可以抵达并被处理;
通过函数sigpending(&pending_set);来获得进程控制块里面的信号未决状态字的值;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | /************************************************************************* > File Name: signal.c > Author: > Mail: > Created Time: 2015年11月21日 星期六 10时21分58秒 ************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> void sig_handler( int num){ if (num == SIGINT){ printf ( "receive the SIGINT: %d\n" , num); } else if (num == SIGQUIT){ printf ( "recevie the SIGQUIT: %d\n" , num); } } void print_sig_set(sigset_t * set) { int i; for (i = 1; i <= 64; ++i){ if (sigismember(set, i)){ putchar ( '1' ); } else { putchar ( '0' ); } } printf ( "\n" ); } int main() { sigset_t block_set; sigset_t pending_set; sigemptyset(&block_set); sigaddset(&block_set, SIGINT); signal (SIGINT, sig_handler); signal (SIGQUIT, sig_handler); sigprocmask(SIG_BLOCK, &block_set, NULL); while (1){ sigpending(&pending_set); print_sig_set(&pending_set); sleep(1); } exit (0); } |
运行结果每一行都是64个数字,这64个数字是进程控制块中信号未决状态字的值;可以看到,刚开始是全部都是0,当进程收到中断信号SIGINT
之后,信号未决状态字的第二个bit被置为了1,表明该信号SIGINT被置为了阻塞;当进程收到退出信号SIGQUIT之后,
信号未决状态字的第三个bit仍然是0;
实例三:
我想让收到退出信号的时候,重新设置SIGINT中断信号的阻塞状态;将SIGINT设置为非阻塞的;但是这种设置仅仅是接触阻塞,
比如如下面的运行结果可以看出:
刚开始的时候信号未决状态字的值为全0,当收到SIGINT中断的时候,bit1被置为1;当再收到SIGQUIT信号的时候,将SIGINT置为非阻塞的,
此时进程同时显示收到SIGQUIT和SIGINT信号,同时未决状态字的bit1被置为了0;当再次收到SIGINT中断的时候,bit1仍然被置为1;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | /************************************************************************* > File Name: signal.c > Author: > Mail: > Created Time: 2015年11月21日 星期六 10时21分58秒 ************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> void sig_handler( int num){ if (num == SIGINT){ printf ( "receive the SIGINT: %d\n" , num); } else if (num == SIGQUIT){ printf ( "recevie the SIGQUIT: %d\n" , num); sigset_t new_set; sigaddset(&new_set, SIGINT); sigprocmask(SIG_UNBLOCK, &new_set, NULL); } } void print_sig_set(sigset_t * set) { int i; for (i = 1; i <= 64; ++i){ if (sigismember(set, i)){ putchar ( '1' ); } else { putchar ( '0' ); } } printf ( "\n" ); } int main() { sigset_t block_set; sigset_t pending_set; sigemptyset(&block_set); sigaddset(&block_set, SIGINT); signal (SIGINT, sig_handler); signal (SIGQUIT, sig_handler); sigprocmask(SIG_BLOCK, &block_set, NULL); while (1){ sigpending(&pending_set); print_sig_set(&pending_set); sleep(1); } exit (0); } |
实例四:
如果我想重新设置SIGINT中断信号的阻塞状态,在主函数中重新设置;实例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | /************************************************************************* > File Name: signal.c > Author: > Mail: > Created Time: 2015年11月21日 星期六 10时21分58秒 ************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> void sig_handler( int num){ if (num == SIGINT){ printf ( "receive the SIGINT: %d\n" , num); } else if (num == SIGQUIT){ printf ( "recevie the SIGQUIT: %d\n" , num); sigset_t new_set; sigaddset(&new_set, SIGINT); sigprocmask(SIG_UNBLOCK, &new_set, NULL); } } void print_sig_set(sigset_t * set) { int i; for (i = 1; i <= 64; ++i){ if (sigismember(set, i)){ putchar ( '1' ); } else { putchar ( '0' ); } } printf ( "\n" ); } int main() { sigset_t block_set; sigset_t pending_set; sigemptyset(&block_set); sigaddset(&block_set, SIGINT); signal (SIGINT, sig_handler); signal (SIGQUIT, sig_handler); sigprocmask(SIG_BLOCK, &block_set, NULL); int time = 10; while ( time ){ sigpending(&pending_set); print_sig_set(&pending_set); sleep(1); time --; } printf ( "first sleep is over.\n" ); sigprocmask(SIG_UNBLOCK, &block_set, NULL); while (1){ sigpending(&pending_set); print_sig_set(&pending_set); sleep(1); } exit (0); } |
从运行结果可以看出,前十秒的情况和实例三一样;当输出first sleep is over.表明前十秒结束,然后将SIGINT中断信号设置为非阻塞状态,
此后的结果表明,每次收到中断信号之后就直接处理,而不是阻塞起来;十秒之后的情况就和实例三不一样了;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南