【Linux系统编程】26.信号、kill、alarm、setitimer

embedded/2024/11/14 2:40:15/

目录

信号

信号共性

信号特质

产生信号

信号相关概念

默认处理动作

信号4要素

常规信号  ​编辑

注意

kill

参数pid

测试代码1

测试结果

测试代码2

测试结果

alarm

参数seconds

返回值

取消闹钟

测试代码3

测试结果1

测试结果2  ​编辑

setitimer

参数which

参数new_value

参数old_value

测试代码4

测试结果

信号集操作函数

信号

信号共性

  • 简单

  • 不能携带大量信息

  • 满足条件才能发送

信号特质

       信号是软件层面上的“中断”,一旦信号产生,无论程序执行到什么位置,都必须立即停止运行,处理信号,处理完成后,再继续执行后续程序。所有信号的产生及处理都是由内核完成。

产生信号

  1. 按键产生

  2. 系统调用产生

  3. 软件条件产生

  4. 硬件异常产生

  5. 命令产生

信号相关概念

未决:产生与递达之间的状态。

递达:产生并且送达到进程,直接被内核处理掉。

信号处理方式

  1. 执行默认处理动作。

  2. 忽略。

  3. 捕捉。

阻塞信号集(信号屏蔽字):本质是位图。用来记录信号的屏蔽状态。一旦被屏蔽的信号,在解除屏蔽之前,一直处于未决态。

未决信号集:本质是位图。用来记录信号的处理状态。该信号集中的信号表示已经产生,但未被处理。

默认处理动作

Term:终止进程。

lgn:忽略信号。

Core:终止进程,生成Core文件。可以查验进程死亡原因,用gdb进行调试。

Stop:停止进程或暂停进程。

Cont:继续运行进程。

信号4要素

信号使用之前,必须先确定其4要素,再进行使用。

  1. 信号编号

  2. 信号名称

  3. 信号对应时间

  4. 信号默认处理动作

man 7 signal

       在标准信号中,有一些信号是有三个“Value”,第一个值通常对alpha和sparc架构有效,中间值针对x86、arm和其他架构,最后一个应用于mips架构。一个‘-’表示在对应架构上尚未定义该信号。

       不同的操作系统定义了不同的系统信号。因此有些信号出现在Unix系统内,也出现在Linux 中,而有的信号出现在FreeBSD或Mac OS中却没有出现在Linux下。

常规信号  

  1. SIGHUP:当用户退出shell时,由该shell启动的所有进程将收到这个信号,默认动作为终止进程。

  2. SIGIN:当用户按下了<Ctrl+C>组合键时,用户终端向正在运行中的由该终端启动的程序发出此信号。默认动作为终止进程。

  3. SIGQUIT:当用户按下<ctrl+\>组合键时产生该信号,用户终端向正在运行中的由该终端启动的程序发出些信号。默认动作为终止进程。

  4. SIGILL:CPU检测到某进程执行了非法指令。默认动作为终止进程并产生core文件。

  5. SIGTRAP:该信号由断点指令或其他trap指令产生。默认动作为终止进程并产生core文件。

  6. SIGABRT:调用abort函数时产生该信号。默认动作为终止进程并产生core文件。

  7. SIGBUS:非法访问内存地址,包括内存对齐出错,默认动作为终止进程并产生core文件。

  8. SIGFPE:在发生致命的运算错误时发出。不仅包括浮点运算错误,还包括溢出及除数为0等所有的算法错误。 默认动作为终止进程并产生core文件。

  9. SIGKILL:无条件终止进程。本信号不能被忽略,处理和阻塞。默认动作为终止进程。它向系统管理员提供了可以杀死任何进程的方法。

  10. SIGUSE1:用户定义的信号。即程序员可以在程序中定义并使用该信号。默认动作为终止进程。

  11. SIGSEGV:指示进程进行了无效内存访问。默认动作为终止进程并产生core文件。

  12. SIGUSR2:另外一个用户自定义信号,程序员可以在程序中定义并使用该信号。默认动作为终止进程。

  13. SIGPIPE:Broken pipe向一个没有读端的管道写数据。默认动作为终止进程。

  14. SIGALRM:定时器超时,超时的时间由系统调用alarm设置。默认动作为终止进程。

  15. SIGTERM:程序结束信号,与SIGKILL不同的是,该信号可以被阻塞和终止。通常用来要示程序正常退出。执行 shell命令Kill时,缺省产生这个信号。默认动作为终止进程。

  16. SIGSTKFLT:Linux早期版本出现的信号,现仍保留向后兼容。默认动作为终止进程。

  17. SIGCHLD:子进程状态发生变化时,父进程会收到这个信号。默认动作为忽略这个信号。

  18. SIGCONT:如果进程已停止,则使其继续运行。默认动作为继续/忽略。

  19. SIGSTOP:停止进程的执行。信号不能被忽略,处理和阻塞。默认动作为暂停进程。

  20. SIGTSTP:停止终端交互进程的运行。按下<ctrl+z>组合键时发出这个信号。默认动作为暂停进程。

  21. SIGTTIN:后台进程读终端控制台。默认动作为暂停进程。

  22. SIGTTOU:该信号类似于SIGTTIN,在后台进程要向终端输出数据时发生。默认动作为暂停进程。

  23. SIGURG:套接字上有紧急数据时,向当前正在运行的进程发出些信号,报告有紧急数据到达。如网络带外数据到达,默认动作为忽略该信号。

  24. SIGXCPU:进程执行时间超过了分配给该进程的CPU时间 ,系统产生该信号并发送给该进程。默认动作为终止进程。

  25. SIGXFSZ:超过文件的最大长度设置。默认动作为终止进程。

  26. SIGVTALRM:虚拟时钟超时时产生该信号。类似于SIGALRM,但是该信号只计算该进程占用CPU的使用时间。默认动作为终止进程。

  27. SGIPROF:类似于SIGVTALRM,它不公包括该进程占用CPU时间还包括执行系统调用时间。默认动作为终止进程。

  28. SIGWINCH:窗口变化大小时发出。默认动作为忽略该信号。

  29. SIGIO:此信号向进程指示发出了一个异步IO事件。默认动作为忽略。

  30. SIGPWR:关机。默认动作为终止进程。

  31. SIGSYS:无效的系统调用。默认动作为终止进程并产生core文件。

34~64. LINUX 的实时信号,它们没有固定的含义,可以由用户自定义。所有的实时信号的默认动作都为终止进程。

注意

       9) SIGKILL和19) SIGSTOP信号,不允许忽略和捕捉,只能执行默认动作。甚至不能将其设置为阻塞。

        只有每个信号所对应的事件发生了,该信号才会被递送,但不一定递达,不应乱发信号!

kill

man 2 kill

参数pid

大于0:发送信号给指定进程。

等于0:发送信号给跟调用kill函数的那个进程处于同一进程组的进程。

小于-1:取绝对值,发送信号给该绝对值所对应的进程组的所有进程。

等于-1:发送信号给有权限发送的所有进程,普通用户基本规则是,发送者实际或有效用户ID==接收者实际或有效用户ID。

测试代码1

用子进程杀了父进程。

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>int main(int argc, char *argv[])
{pid_t JinCheng_ID;JinCheng_ID = fork();if (JinCheng_ID > 0) //父进程{printf("这是父进程,该进程ID是%d。开始进入死循环。\n", getpid());while (1){printf("这是父进程,已在死循环。\n");sleep(1);}}else if (JinCheng_ID == 0) //子进程{printf("这是子进程,该进程ID是%d。先睡一会再杀父进程。\n", getpid());sleep(3);printf("这是子进程,该进程ID是%d。睡醒了,我杀。\n", getpid());kill(getppid(),SIGKILL);printf("这是子进程,该进程ID是%d。杀完了,拜拜。\n", getpid());}return 0;
}

测试结果

 

测试代码2

杀进程组

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>int main(int argc, char *argv[])
{pid_t JinCheng_ID;JinCheng_ID = fork();if (JinCheng_ID > 0) //父进程{printf("这是父进程,该进程ID是%d。开始进入死循环。\n", getpid());while (1){printf("这是父进程,已在死循环。\n");sleep(1);}}else if (JinCheng_ID == 0) //子进程{printf("这是子进程,该进程ID是%d。先睡一会再杀进程组。\n", getpid());sleep(3);printf("这是子进程,该进程ID是%d。睡醒了,我杀。\n", getpid());kill(0, SIGKILL);printf("这是子进程,该进程ID是%d。杀完了,拜拜。\n", getpid());}return 0;
}

测试结果

进程组被杀后,子进程最后的输出不再进行输出。

 

alarm

定时发送SIGALRM给当前进程。

实际时间=用户时间+内核时间+等待时间,代码优化,优先从IO下手。

man 2 alarm

参数seconds

定时秒数。

返回值

上次剩余的时间。

取消闹钟

alarm(0);

测试代码3

查看程序1秒钟的计数次数。

#include <stdio.h>
#include <unistd.h>int main(int argc, char *argv[])
{int i = 0;alarm(1); //定时1秒while (1){printf("%d\n", i++);}return 0;
}

测试结果1

测试结果2  

setitimer

设置定时器(闹钟)。 可代替alarm函数。精度微秒us,可以实现周期定时。

man 2 setitimer

参数which

指定定时方式。

  • ITIMER_REAL:自然定时,计算自然时间,信号是14)SIGLARM。

  • ITIMER_VIRTUAL:虚拟空间计时(用户空间),只计算进程占用cpu的时间,信号是26)SIGVTALRM。

  • ITIMER_PROF:运行时计时(用户+内核),计算占用cpu及执行系统调用的时间,信号是27)SIGPROF。

参数new_value

定时秒数。

struct itimerval {struct timeval it_interval; //后续每个中断的间隔执行时间struct timeval it_value;    //第一次执行中断的时间
};struct timeval {time_t      tv_sec;         //秒suseconds_t tv_usec;        //微秒
};
struct itimerval {struct timeval {	//后续每个中断的间隔执行时间time_t      tv_sec;         //秒suseconds_t tv_usec;        //微秒}it_interval;struct timeval {	//第一次执行中断的时间time_t      tv_sec;         //秒suseconds_t tv_usec;        //微秒}it_value;
};

参数old_value

传出参数,上次定时剩余的时间。

测试代码4

周期性输出内容。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <signal.h>void ChuLi_HanShu()
{printf("你好,世界!\n");
}int main(int argc, char *argv[])
{int i = 0;struct itimerval new_value, old_value;signal(SIGALRM, ChuLi_HanShu); //注册SIGALRM信号的捕捉处理函数//2秒后开始第1次中断new_value.it_value.tv_sec=2;new_value.it_value.tv_usec=0;//每5秒来一次中断new_value.it_interval.tv_sec=5;new_value.it_interval.tv_usec=0;if(setitimer(ITIMER_REAL,&new_value,&old_value)==-1){perror("设置中断错误");exit(1);}while (1){printf("%d秒\n", i++);sleep(1);}return 0;
}static

测试结果

信号集操作函数

sigset_t set;	//自定义信号集
sigemptyset(sigset_t *set);		//清空信号集
sigfillset(sigset_t *set);		//全部置1
sigaddset(sigset_t *set,int signum);	//每一个信号添加到集合中
sigdelset(sigset_t *set,int signum);	//将一个信号从集合中移除
sigismember(const sigset_t *set,int signum);	//判断一个信号是否在集合中。返回值:1:在;0:不在。

http://www.ppmy.cn/embedded/20317.html

相关文章

最最普通程序员,如何利用工资攒够彩礼,成为人生赢家

今天我们不讲如何提升你的专业技能去涨工资&#xff0c;不讲面试技巧如何跳槽涨工资&#xff0c;不讲如何干兼职赚人生第一桶金&#xff0c;就讲一个最最普通的程序员&#xff0c;如何在工作几年后&#xff0c;可以攒够彩礼钱&#xff0c;婚礼酒席钱&#xff0c;在自己人生大事…

力扣经典150题第四十题:同构字符串

目录 力扣经典150题第四十题&#xff1a;同构字符串引言题目详解解题思路代码实现示例演示复杂度分析 力扣经典150题第四十题&#xff1a;同构字符串 引言 本篇博客介绍了力扣经典150题中的第四十题&#xff1a;同构字符串。题目要求判断两个字符串 s 和 t 是否是同构的。 同…

JavaScript 中 ES6

在ES6&#xff08;ECMAScript 2015&#xff09;中&#xff0c;JavaScript引入了一些新的语法和特性来支持面向对象编程&#xff08;OOP&#xff09;。下面是对ES6中面向对象编程的详细解释&#xff1a; 类&#xff08;Class&#xff09;&#xff1a; ES6引入了类的概念&#xf…

8 Dubbo 应用案例(动手实操一波)

概述 案例相关配置可参考 GitHub:https://github.com/apache/dubbo-spring-boot-project/tree/master/dubbo-spring-boot-samples 创建服务接口项目 创建一个名为 hello-dubbo-service-user-api 的项目,该项目只负责定义接口 POM <?xml version="1.0" enco…

PotatoPie 4.0 实验教程(29) —— FPGA实现摄像头图像均值滤波处理

图像的均值滤波简介 图像均值滤波处理是一种常见的图像处理技术&#xff0c;用于降低图像中噪声的影响并平滑图像。该方法通过在图像中滑动一个固定大小的窗口&#xff08;通常是一个正方形或矩形&#xff09;&#xff0c;将窗口中所有像素的值取平均来计算窗口中心像素的新值…

Ubuntu中的 Everything 搜索软件 ==> fsearch

本文所使用的 Ubuntu 系统版本是 Ubuntu 22.04 ! 在 Windows 中&#xff0c;我经常使用 Everything 来进行文件搜索&#xff0c;搜索效率比 Windows 自带的高出千百倍。 那么在 Ubuntu 系统中&#xff0c;有没有类似的软件呢&#xff1f;那必须有&#xff0c;它就是 FSearch 。…

web server apache tomcat11-25-Advanced IO and Tomcat

前言 整理这个官方翻译的系列&#xff0c;原因是网上大部分的 tomcat 版本比较旧&#xff0c;此版本为 v11 最新的版本。 开源项目 从零手写实现 tomcat minicat 别称【嗅虎】心有猛虎&#xff0c;轻嗅蔷薇。 系列文章 web server apache tomcat11-01-官方文档入门介绍 web…

Mac下使用homebrew管理多版本mysql同时启动

Mac下使用homebrew管理多版本mysql同时启动 思路 给每个版本分配不同的数据目录和配置文件即可 本文尝试了使用 brew 安装管理多个MySQL版本&#xff0c;同时运行、直接切换 安装 如果已有数据文件请自行备份以及使用 安装 mysql 5.7 brew install mysql5.7在 /opt/home…