系统编程-信号-总体概述和signal基本使用
信号章节 -- 信号章节总体概要

信号基本概念

信号是异步事件,发送信号的线程可以继续向下执行而不阻塞。
信号无优先级。
1到31号信号是非实时信号,发送的信号可能会丢失,不支持信号排队。
31号信号到64是实时信号, 发送的信号都会被接收, 支持信号排队。
信号在Linux内核头文件中的宏定义

信号的处理

由于进程启动时,SIGUSR1和SIGUSR2被忽略,一般我们可以在有需要时,去捕获这两个信号,进而调用自己的处理函数。相应的,我们的程序其他地方去发送相应的信号。
signal函数原型 以及使用时所要包含的头文件

和下面的是等价的:

实验1 signal基本使用
实验1.1
#include <stdio.h>
#include <signal.h>
#include <unistd.h> //定义信号处理函数
//signo: 进程捕获到的信号
void sig_handler(int signo){
printf("%d, %d occured \n", getpid(), signo);
} int main(){ #if 1 // 屏蔽这块代码,就是不捕获这俩信号
//向内核登记信号处理函数以及信号值
if(signal(SIGTSTP, sig_handler) == SIG_ERR){ perror("signal error");
}
if(signal(SIGINT, sig_handler) == SIG_ERR){ perror("signal sigint error");
}
#endif while(1){
sleep(1);
printf("- hello -\n");
}; return 0;
}
编译运行

同时,根据这里的打印也可以看出,
SIGINT信号就是2号信号, 我们在键盘上按下CTRL+C就可以发送该信号了。
SIGTSTP信号就是20号信号,我们在键盘上按下CTRL+Z就可以发送该信号了。20号信号的备注就是 Keyboard stop, 即通过键盘发信号让进程停止。

实验1.2
如果屏蔽实验1内捕获这俩信号的代码块,运行效果如下

常用知识点补充:
19) SIGSTOP 20) SIGTSTP
19号信号和29号信号的相同点: 都可以使得进程暂停,并且收到SIGCONT信号后可以让进程重新运行。
19号信号和29号信号的不同点: SIGSTOP不可以捕获(即使用信号处理函数)。
那么,我们来让刚才停止的a.out继续运行吧:
先查看a.out的pid


可见a.out的pid是8349
我们通过kill来发SIGCONT信号(18号信号)让a.out继续运行

可见,a.out又继续运行起来了,
然而,需要注意的是,通过18号信号被继续执行的进程:当终端内按下CTRL+C,则不能使得该进程终止了;且按下CTRL+Z,终端内也毫无迹象;但是可以通过kill -9被杀死。
根据实测,是这样的,事实胜于雄辩。这个问题的原因以及背后隐藏的暂时我们还不知的相应知识点,可以留待以后探索,我们先暂且知道这么一回事就行了。
实验2 SIG_DFL 和 SIG_IGN 使用
#include <stdio.h>
#include <signal.h>
#include <unistd.h> //定义信号处理函数
//signo: 进程捕获到的信号
void sig_handler(int signo){
printf("%d, %d occured \n", getpid(), signo);
} int main(){
printf("pid: %d \n", getpid()); #if 1 // 屏蔽这块代码,就是不捕获这俩信号
//向内核登记信号处理函数以及信号值
if(signal(SIGTSTP, SIG_IGN) == SIG_ERR){ perror("signal error");
}
if(signal(SIGINT, SIG_DFL) == SIG_ERR){ perror("signal sigint error");
}
#endif while(1){
sleep(1);
printf("- hello -\n");
}; return 0;
}

此时,按下CTRL+Z对程序运行将毫无影响,而CTRL+C则采用默认方式,即结束进程。
实验3 SIGUSR1 和 SIGUSR2 使用
注意,这两个信号在进程启动时默认是被忽略的。
#include <stdio.h>
#include <signal.h>
#include <unistd.h> //定义信号处理函数
//signo: 进程捕获到的信号
void sig_handler(int signo){
printf("%d, %d occured \n", getpid(), signo);
} int main(){
printf("pid: %d \n", getpid()); #if 1 // 屏蔽这块代码,就是不捕获这俩信号
//向内核登记信号处理函数以及信号值
if(signal(SIGUSR1, sig_handler) == SIG_ERR){
perror("signal error");
}
if(signal(SIGUSR2, sig_handler) == SIG_ERR){
perror("signal sigint error");
}
#endif while(1){
sleep(1);
printf("- hello -\n");
}; return 0;
}
编译运行,同时在另一个终端内发送信号 kill -SIGUSR1 10452 、 kill -SIGUSR2 10452

实验4
知识点:SIGKILL 和 SIGSTOP不能被忽略,也不能被捕获。
本实验将尝试捕获SIGKILL和SIGSTOP,并以SIG_IGN的方式进程处理。
核心代码展示:

编译运行将返回SIG_ERR,如下图所示

实验5 SIGCHLD
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h> //定义信号处理函数
//signo: 进程捕获到的信号
void sig_handler(int signo){
printf("%d, %d occured \n", getpid(), signo);
wait(NULL);
} int main(void)
{
pid_t pid; if(signal(SIGCHLD, sig_handler) == SIG_ERR){
perror("signal error");
} pid = fork();
if (pid < 0)
{
printf("fork error");
}
else if (pid == 0) /* first child : 子进程 */
{
sleep(2);
printf("pid: child =%ld\n", (long)getpid());
exit(0);
} // 使用信号的方式,父进程不必在此处阻塞调用wait,可以继续向下执行自己的任务。
while(1){
sleep(1);
printf("father can does his own things \n");
}
}
编译运行:

实验中可见,父进程收到了子进程的17号信号,17号信号就是SIGCHLD信号(或写作SIGCLD)

使用信号来回收子进程后,父进程不必在阻塞调用wait,可以继续向下执行自己的任务。这个例子充分体现出了信号是一个异步事件。
在父进程还存活的期间,子进程退出将不会产生僵尸进程。
PS:父进程死后,肯定不会有其子进程还仍然是僵尸进程,因为一个子进程们会在其父进程死后被1号进程领养,进而被1号进程回收掉所占用的系统资源。
.
系统编程-信号-总体概述和signal基本使用的更多相关文章
- UNIX环境高级编程——信号基本概述和signal函数
一.为了理解信号,先从我们最熟悉的场景说起:1. 用户输入命令,在Shell下启动一个前台进程.2. 用户按下Ctrl-C,这个键盘输入产生一个硬件中断.3. 如果CPU当前正在执行这个进程的代码,则 ...
- Linux C系统编程:信号与定时器的使用
#include <stdio.h> #include <signal.h> void do_alarm(int num); int main(void) { //注册一个定时 ...
- Linux系统编程—信号捕捉
前面我们学习了信号产生的几种方式,而对于信号的处理有如下几种方式: 默认处理方式: 忽略: 捕捉. 信号的捕捉,说白了就是抓到一个信号后,执行我们指定的函数,或者执行我们指定的动作.下面详细介绍两个信 ...
- Linux系统编程——信号
目录 信号的介绍 信号的机制 信号的编号 Linux常规信号一览表 信号的产生 终端按键产生信号 硬件异常产生信号 kill函数/命令产生信号 信号的操作函数 信号集设定 sigprocmask函数 ...
- linux系统编程--信号
信号的概念 man 7 siganl 查看man手册 信号在我们的生活中随处可见, 如:古代战争中摔杯为号:现代战争中的信号弹:体育比赛中使用的信号枪......他们都有共性:1. 简单 2. 不能 ...
- Linux系统编程—信号集操作函数
先来回顾一下未决信号集是怎么回事. 信号从产生到抵达目的地,叫作信号递达.而信号从产生到递达的中间状态,叫作信号的未决状态.产生未决状态的原因有可能是信号受到阻塞了,也就是信号屏蔽字(或称阻塞信号集, ...
- 系统编程-信号-信号发送kill、raise、alarm
信号发送 kill 和 raise函数 kill函数参数详解: 实验1 raise和kill 的使用 #include <stdio.h> #include <signal.h> ...
- --系统编程-网络-tcp客户端服务器编程模型、socket、htons、inet_ntop等各API详解、使用telnet测试基本服务器功能
PART1 基础知识 1. 字节序 网络字节序是大端字节序(低地址存放更高位的字节), 所以,对于字节序为小端的机器需要收发网络数据的场景,要对这些数据进行字节序转换. 字节序转换函数,常用的有四个: ...
- linux系统编程之信号(三):信号安装、signal、kill,arise讲解
一,信号安装 如果进程要处理某一信号,那么就要在进程中安装该信号.安装信号主要用来确定信号值及进程针对该信号值的动作之间的映射关系,即进程将要处理哪个信号:该信号被传递给进程时,将执行何种操作. li ...
随机推荐
- html5 & iOS
html5 & iOS Apple App Store审核指南 https://developer.apple.com/app-store/review/guidelines/ Apple审核 ...
- flutter web in action
flutter web in action flutter for web https://flutter.dev/web https://flutter.dev/docs/get-started/w ...
- 2021年-在windwos下如何用TOMACT发布一个系统(完整配置案列)
2021年新年第一篇:博主@李宗盛-关于在Windwos下使用TOMCAT发布一个系统的完成配置案列. 之前写过关于TOMCAT的小篇幅文档,比较分散,可以作为对照与参考. 此篇整合在一起,一篇文档写 ...
- SpringBoot2.1整合Mybatis-Generator以及tk.mybatis
1:添加依赖 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http ...
- Mysql 高可用(MHA)-读写分离(Atlas)-分布式架构(Mycat)
Mysql 高可用(MHA)-读写分离(Atlas) 1. 搭建主从复制(一主两从) 1.1 准备环境 1 主库:10.0.0.51/db01 2 从库:10.0.0.52/db02,10.0.0.5 ...
- 重复代码的克星,高效工具 VSCode snippets 的使用指南
为什么要用 snippets(代码段)? 不管你使用何种编程语言,在我们日常的编码工作中,都会存在有大量的重复代码编写,例如: 日志打印: console.log,log.info('...') 输出 ...
- 如何进BAT,有了这个篇面试秘籍,成功率高达80%!!(附资料)
多年前自己刚来北京找工作的时候,面了一个星期 面了七八家公司才拿到一个offer.而上次跳槽面了不到10家公司基本全过而且都给到了期望的薪资,本来自己在面试前没想到能够这么顺利,回想起来还是自己准备的 ...
- sqlyog如何增删改查?
转: sqlyog如何增删改查? 下面是一道完整的 sqlyog 增删改查的练习, 顺着做下去,可以迅速掌握. 1. 创建部门表dept,并插入数据: 2. 创建emp员工表,并插入数据: sql 代 ...
- React源码 commit阶段详解
转: React源码 commit阶段详解 点击进入React源码调试仓库. 当render阶段完成后,意味着在内存中构建的workInProgress树所有更新工作已经完成,这包括树中fiber节点 ...
- 31Si2CrMoB
转: 31Si2CrMoB 31Si2CrMoB是推土机用钢的一种耐磨钢:此钢有很高的强度和韧度,适合于推土机XX.31Si2CrMoB冶炼技术工艺:电弧炉冶炼,初轧开坯.钢板轧制:可√189-170 ...