当前位置: 首页 > news >正文

Linux系统编程---进程间Signal信号通信

0、说明

        在前面几篇博客笔记文章对Linux系统编程部分的进程知识体系做了完善的梳理,这篇文章将继续在前几篇的基础上,对Linux系统编程进程间通信的知识点进行讲解。

        本文主要对信号的内容进行讲解,因为内容比较多,所以信号集部分的内容,将在下一篇博客文章中进行梳理。

        有需要的博客网友,可以在我的Linux系统专栏中查询参考交流:

系统编程_奔跑的蜗牛!的博客-CSDN博客https://blog.csdn.net/weixin_49337111/category_12952742.html?spm=1001.2014.3001.5482

1、信号基础梳理

(1)、什么是信号?

        在Linux操作系统中,进程间通信(Inter-Process Communication, IPC)是一个重要的概念,它允许不同的进程之间交换信息或同步它们的行为。信号(signal)是一种基本的进程间通信机制,用于通知一个进程发生了某个特定事件。

        信号是一种异步通信机制,一般情况下,进程什么时候会收到信号、收到什么信号是无法事先预料的。(就像你家的门铃,你不知道它什么时候会响,但是门铃响的时候我们可以下楼开门(处理))

(2)、Linux中的信号有哪些?

        在Linux终端中,可以通过 kill -l 查看系统支持的信号。

        可以看见,Linux 系统中有许多信号,其中前面 31 个信号都有一个特殊的名字,对应一个特殊的事件,比如 1 号信号 SIGHUP(Signal Hang UP),表示每当系统中的一个控制终端被关闭(即挂断,hang up)时,即会产生这个信号,有时会将他们称为非实时信号,这些信号都是从 Unix 系统继承下来的,它们还有个名称叫“不可靠信号”

        这些信号有如下特点:

        ①、非实时信号不排队,信号的响应会相互嵌套(假设正在响应1号信号的时候收到9号信号则会在响应一号信号的过程中去响应9号信号)。

        ②、如果目标进程没有及时响应非实时信号,那么随后到达的该信号将会被丢弃。(被挂起的信号列表中是不存在相同的信号)

        ③、每一个非实时信号都对应一个系统事件,当这个事件发生时,将产生这个信号。(当某一个特定的系统时间会自动产生一个信号)

        ④、如果进程的挂起信号中含有实时和非实时信号,那么进程优先响应实时信号并且会从大到小依此响应,而非实时信号没有固定的次序。

        后面的 31 个信号(从 SIGRTMIN[34] 到 SIGRTMAX[64])是 Linux 系统新增的实时信号,也被称为“可靠信号”

        这些信号有如下特点:

        ①、实时信号的响应次序按接收顺序排队,不嵌套。

        ②、即使相同的实时信号被同时发送多次,也不会被丢弃,而会依次挨个响应

        ③、实时信号没有特殊的系统事件与之对应。(需要用户自己去产生设置)

        下图为信号和其对应的注释说明:

        ①、上面这个表中列出来的信号的“值”,在 x86、PowerPC 和 ARM 平台下是有效的,但是别的平台的信号值可能跟这个表的不一致

        ②、“备注”部分中注明的事件发生时会产生相应的信号,但并不是说该信号的产生就一定发生了这个事件。事实上,任何进程都可以使用函数 kill( )来产生任何信号

        ③、信号 SIGKILL(9)SIGSTOP(19)(18号信号也可能不能被捕获??) 是两个特殊的信号,他们不能被忽略阻塞捕捉只能按缺省动作来响应

        除了这两个信号之外的其他信号,接收信号的目标进程按照如下顺序来做出反应:

        A) 如果该信号被阻塞,那么将该信号挂起,不对其做任何处理,等到解除对其阻塞为止

                否则进入 B。

        B) 如果该信号被捕捉,那么进一步判断捕捉的类型

                B1) 如果设置了响应函数,那么执行该响应函数

                B2) 如果设置为忽略,那么直接丢弃该信号

                否则进入 C。

        C) 执行该信号的缺省动作

(3)、如何发信号给进程?

        方法一:

1)首先查看目标进程的PID号: ps -ef

Snail@ubuntu:~/Desktop/process$ ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 14:59 ?        00:00:05 /sbin/init auto noprompt
root           2       0  0 14:59 ?        00:00:00 [kthreadd]
root           3       2  0 14:59 ?        00:00:00 [pool_workqueue_release]
root           4       2  0 14:59 ?        00:00:00 [kworker/R-rcu_g]
...

2)通过kill命令发送某一信号给该进程,例如发送信号9,就是杀死进程。

kill -9 4630
kill -SIGKILL 4630  或者 kill -KILL 4630

        方法二:

        直接通过killall命令给进程名字发送信号

        killall -9 a.out

        killall -SIGKILL a.out 或者 killall -KILL a.out

       只要名字为a.out,都会收到这个信号。

2、信号API接口

(1)、发送信号给其它进程:kill

函数功能:向指定进程或者进程组,发送一个指定的信号函数原型:#include <sys/types.h>#include <signal.h>int kill(pid_t pid, int sig);函数参数:
pid:要发送信号的目标进程 ID。pid > 0:向 PID 等于 pid 的指定进程发送信号。pid == 0:向调用进程所在的进程组中的所有进程发送信号。pid < -1:向进程组 ID 等于 pid 的绝对值的所有进程发送信号。pid == -1:向所有有权限发送信号的进程发送信号(一般不包括某些系统进程)。sig:要发送的信号编号SIGTERM:终止进程。SIGKILL:强制终止进程。SIGHUP:挂起信号。SIGSTOP:暂停进程。SIGCONT:继续被暂停的进程。...函数返回值:成功时返回 0。出错时返回 -1,并设置 errno 表示错误原因。

(2)、捕捉信号:signal

函数功能:捕捉一个指定的信号,即预先为某信号的到来做好准备函数原型:#include <signal.h>typedef void (*sighandler_t)(int);sighandler_t signal(int signum, sighandler_t handler);函数参数:signum:要捕获或忽略的信号编号。handler:指向自定义信号处理函数的指针。或者可以使用以下两个特殊值之一:SIG_DFL:使用默认处理方式(如终止进程);SIG_IGN:忽略该信号。函数返回值:成功时返回前一个信号处理函数的指针(即旧的处理程序)。出错时返回 SIG_ERR,并设置 errno 表示错误原因。

(3)、挂起进程:pause

函数功能:用于挂起当前进程,直到它接收到一个信号为止。函数原型:#include <unistd.h>int pause(void);函数参数:void:NONE函数返回值:始终返回 -1,并且设置 errno 为 EINTR,表示被信号中断。

(4)、给自己发送信号:raise

函数功能:用于向当前进程发送一个信号(signal)。函数原型:#include <signal.h>int raise(int sig);函数参数:sig:要发送的信号编号。函数返回值:成功返回 0失败返回非零值   

3、信号的处理

 (1)、忽略(将信号丢弃)

signal(signum,SIG_IGN); //signal   ignore

(2)、 缺省(默认动作)

signal(signum,SIG_DFL);

(3)、捕捉(去执行指定的函数)

signal(signum,function);

(4)、阻塞(信号挂起)

        设置阻塞之后,来了阻塞的指定信号,并不是将信号丢弃,而是将信号挂起,等到解除阻塞之后才去响应这个信号。

        注意:9) SIGKILL 和 19) SIGSTOP 这两个信号不能被忽略,阻塞、捕捉。必须是执行默认动作

4、编程实现

        signal_demo.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>void signalHandle(int signum)
{printf("\nCautgh Signal:%d\n", signum);switch(signum){case SIGINT:printf("OK, you kill me success!\n");exit(signum);break;case SIGUSR1:printf("Hello, This signal from myself!\n");break;}
}int main(int argc, char **argv)
{signal(SIGINT, signalHandle);signal(SIGUSR1, signalHandle);int cnt = 0;while(1){printf("I am still alive!\n");sleep(3);if(++cnt == 5)    {raise(SIGUSR1);}}return 0;
}

        signal_demo.c文件执行的结果如下图所示:

相关文章:

  • el-table计算表头列宽,不换行显示
  • SKNet、空间注意力介绍
  • 如何使用Java生成图像验证码
  • Python学习笔记--Django的安装和简单使用(一)
  • 基于php人力劳务招聘系统开发功能需求分析【源码】
  • window.open(url) 和 window.location.href = url
  • 【PostgreSQL】超简单的主从节点部署
  • python+open3d获取点云的最小外接球体及使用球体裁剪点云
  • CF后台如何设置TCP 和 UDP 端口?
  • 电涌冲击测试领域的精密测量技术研究与应用
  • [论文笔记] 超详细解读DeepSeek v3全论文技术报告
  • 【前端】每日一道面试题2:解释CSS盒模型的box-sizing属性,以及它在响应式布局中的作用。
  • 雷赛伺服电机
  • x64dbg技巧
  • 前端缓存踩坑指南:如何优雅地解决浏览器缓存问题?
  • 【计算机哲学故事1-3】默认设置:在有限的系统里,决定你想成为什么
  • Linux:libc库简单设计
  • RAG技术在测试用例生成中的应用
  • Android RecyclerView自带的OnFlingListener,Kotlin
  • 力扣-142.环形链表II
  • 明明睡够了,怎么还有黑眼圈?可能是身体在求救
  • 美英达成贸易协议,美股集体收涨
  • 国家主席习近平同普京总统举行小范围会谈
  • 老铺黄金拟配售募资近27亿港元,用于门店拓展扩建及补充流动资金等
  • 著名国际关系理论家、“软实力”概念提出者约瑟夫•奈逝世
  • 外交部:应美方请求举行贸易代表会谈,中方反对美滥施关税立场没有变化