信号章节 -- 信号章节总体概要

信号基本概念

信号是异步事件,发送信号的线程可以继续向下执行而不阻塞。

信号无优先级。

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号进程回收掉所占用的系统资源。

.

最新文章

  1. Webpack:前端资源模块化管理和打包工具
  2. 关于linux下system()函数的总结
  3. Reverse Core 第三部分 - 21章 - Windows消息钩取
  4. linux 压缩命令详解
  5. python3 连接SQLserver
  6. javaBean List Map json(转)
  7. hdu
  8. iOS之Scanning的实现
  9. 不知道帐号密码的情况下完全重装Mac Min的OS X10.7系统
  10. 刑事案件的构成要素 zt
  11. oracle object_id和data_object_id的区别
  12. websocket以及自定义协议编程一些总结
  13. Bootstrap_排版_列表
  14. HDU2527:Safe Or Unsafe(哈弗曼树)
  15. Machine Learning—Linear Regression
  16. Hibernate中自带ID的generator的含义
  17. C#抓取数据、正则表达式+线程池初步运用
  18. Nginx-动态路由升级版
  19. 73. Set Matrix Zeroes(中等)
  20. Python_语法和界面设计

热门文章

  1. website text select notes menu
  2. Clean Code of JavaScript
  3. TypeScript &amp; Advanced Types
  4. NGK全球启动大会正式启动,资产上链的前景与机会在哪?
  5. 链表、栈、队列、KMP相关知识点
  6. 面试必知:String、StringBuilder、StringBuffer的区别
  7. 《C++ Primer》笔记 第9章 顺序容器
  8. PAT-1154(Vertex Coloring )+map使用+vector建图+set的使用
  9. linux_MYSQL 数据库自动备份并压缩和删除历史备份
  10. WPF 基础 - 绘画 1) 线段、矩形、圆弧及填充色