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

【Linux系统编程】:信号(1)——前置知识,了解信号

1.进程与信号的关系

Unix信号是一种用于Unix信号是一种用于进程间通信的异步通知机制,用于通知进程某个事件已经发生,例如进程终止、中断等。
https://en.wikipedia.org/wiki/Signal_(IPC)
这说明进程需要识别+处理信号,但在接收到信号前,进程就应该知道该怎么处理信号,所以进程的信号处理机制应该属于信号的内置功能,在接收到信号后,进程会在合适的时间处理该信号,在“接收到处理”的这一时间段中,进程需要保存信号

2.信号的预备知识

2.1 了解前台进程和后台进程

我们之前运行可执行文件,在这里插入图片描述
都是在前台运行,如果我们在程序名后加上取地址(&),该进程就会在后台运行。
前台运行和后台运行有什么区别呢?(注意:程序是静态的,执行程序,一般就会创建进行)
我们可以用ctrl+c中断前台进程的运行,但中断不了后台进程。在这里插入图片描述
这是因为后台进程不与用户直接交互,只有前台进程才会通过图形用户界面(GUI)或命令行界面(CLI)与用户进行交互,响应用户的输入和指令,且一个终端(会话/控制台窗口)一般只会有一个前台进程,可以有多个后台进程。

  • 前台程序通常指的是与用户直接交互的应用程序或界面,它负责处理用户的输入和输出。
  • 后台程序(也称为后台进程或服务)是在计算机系统中运行的,但不直接与用户交互的程序。它们通常在用户不知道或不需要直接干预的情况下执行任务。

2.1 Ctrl+C的本质

那么为什么ctrl+c可以中断前台进程呢?
因为键盘输入ctrl+c会被转换为前台进程识别的2号信号SIGINT,SIGINT信号的默认行为是终止自己。我们可以查看一下所有信号(本质上都是宏),一共62个。(没有32、33)
在这里插入图片描述
在这里插入图片描述
为什么进程收到2号信号SIGINT就会终断自己呢?
一般而言,进程收到信号有三类处理方式:在这里插入图片描述
注意:自定义动作就是提供一个信号处理函数,要求内核在处理该信号时切换到用户态执行这个处理函数,这种方式称为信号的捕捉(Catch)。
SIGINT的默认动作就是终止自己。
我们可以编写程序验证一下,进程是因为收到信号2才退出的。
我们先认识一下signal函数,在这里插入图片描述
在 C 语言中,signal() 函数用于设置一个信号处理程序,当指定的信号发生时,操作系统会调用这个信号处理程序来处理该信号。

  • 参数:
    • signum:要处理的信号编号(或者宏,SIGINT本质上是一个宏,其值就是2)。例如,SIGINT 表示用户中断信号(通常是 Ctrl+C),SIGSEGV 表示段错误信号,等等。
    • handler:这是一个指向信号处理函数的指针,或者可以是两个特殊的宏 SIG_IGN(忽略信号)和 SIG_DFL(采用默认的信号处理行为)。
      注意:函数指针
  • 返回值
    • 成功时,返回之前的信号处理程序(即旧的信号处理程序)。
    • 失败时,返回 SIG_ERR,并设置 errno 以指示错误原因。
      所以我们可以编写一个函数(自定义接收到SIGINT后进程的处理方式),用来替代SIGINT原来的默认行为(终止进程),当我们运行程序后,按下Ctrl+C,程序没有终止而是执行了我们编写函数的内容,就代表“SIGINT的默认行为确实是终止进程”。
#include <iostream>
#include <unistd.h>
#include <signal.h>
using namespace std;

//signo表示默认行为(旧的)
//函数体表示自定义的行为(新的)
void myhandler(int signo)
{
    cout << "catch signal " << signo << endl;
}
int main()
{
    signal(SIGINT, myhandler);//也可以用2替代SIGINT
    while(true)
    {
        cout << "hello world" << endl;
        sleep(1); 
    }
    return 0;
}

运行结果:

在这里插入图片描述
验证无误。

可是这样我们就无法用“Ctrl+C”终止当前进程了,我们可以用“kill -9”杀掉这个进程,也可以在myhandler函数体中,加上进程退出语句exit(1),在这里插入图片描述
这样输入一次Ctrl+C后,进程就会退出。

2.3 Ctrl+C如何变成信号的

Ctrl+C 组合键在 Linux 和其他类 Unix 系统中被用来发送一个特定的信号给正在运行的前台进程,这个信号通常被称为 SIGINT(中断信号)。以下是 Ctrl+C 如何变成信号并影响前台进程的详细过程:

1. 用户输入

  • 当用户在终端或命令行界面中按下 Ctrl+C 组合键时,这是一个明确的用户操作,表示希望中断当前正在运行的前台进程。

2. 终端程序捕获

  • 终端程序(如 bash、zsh 等 shell)会捕获这个按键组合。终端程序是用户与操作系统内核之间的一个接口,它负责接收用户的输入并将其转换为相应的操作或命令。

3. 发送信号给前台进程

  • 终端程序识别到 Ctrl+C 后,会生成一个 SIGINT 信号,并将其发送给当前正在运行的前台进程。前台进程是指当前在终端中运行且与用户交互的进程。

4. 内核处理信号

  • 操作系统内核接收到终端程序发送的信号后,会将其传递给目标前台进程。内核是操作系统的核心部分,负责管理硬件、内存、进程等系统资源。

5. 进程处理信号

  • 前台进程收到 SIGINT 信号后,会根据信号的默认处理方式或自定义处理方式来做出相应的响应。
    • 默认处理方式:大多数情况下,SIGINT 信号的默认处理方式是终止进程的执行。也就是说,如果进程没有捕获或忽略这个信号,那么它会被终止。
    • 自定义处理方式:有些程序可能会捕获 SIGINT 信号,并进行自定义的处理,比如保存数据、释放资源等,然后再退出。这通常是通过在程序中注册一个信号处理函数来实现的。

6. 进程终止或继续

  • 根据进程对 SIGINT 信号的处理方式,进程可能会被终止,也可能会继续执行(如果它捕获了信号并进行了自定义处理)。

注意事项

  • Ctrl+C 发送的 SIGINT 信号是前台进程组信号,这意味着如果当前有多个进程组成了一个前台进程组,那么它们都会收到这个信号。
  • 除了 SIGINT 外,Linux 系统中还有许多其他信号,如 SIGKILL(强制终止进程)、SIGTERM(请求终止进程)等,它们都可以通过不同的方式发送给进程,以实现对进程的控制和管理。
  • 前台进程在运行过程中用户随时可能按下Ctrl-C而产生一个信号,也就是说该进程的用户空间代码执行到任何地方都有可能收到SIGINT信号而终止,所以信号相对于进程的控制流程来说是异步(Asynchronous)的

来源:https://yiyan.baidu.com/
可参考
linux信号| 学习信号四步走 | 学习信号需要打通哪些知识脉络?
键盘输入流程

3.不是所有的信号都可以被signal()捕捉

3.1捕捉信号3(SIGQUIT)

我们用signal()来捕捉3号信号,

#include <iostream>
#include <unistd.h>
#include <signal.h>
using namespace std;

void myhandler(int signo)
{
    cout << "catch signal " << signo << endl;
}
int main()
{
    signal(3, myhandler);
    while(true)
    {
        cout << "hello world" << endl;
        sleep(1); 
    }

    return 0;
}

重新编译并运行,
在这里插入图片描述
但我们向进程myprocess发送3号信号时,
在这里插入图片描述
旧的默认行为被替换成打印“catch signal:3”,

3.2 捕捉信号19(SIGSTOP)

将上面代码中

    signal(3, myhandler);

改成

    signal(19, myhandler);

重新编译并运行,在这里插入图片描述
向该程序发送19号信号后,进程直接终止,说明19号信号没有被signal捕获。
我们可以写一个循环,按照上面的方法一一测试所有的信号是否能被捕捉。
前31个信号中,只有9号信号和19号信号无法被捕捉。在这里插入图片描述


http://www.kler.cn/a/445650.html

相关文章:

  • 轻松上手:使用 Vercel 部署 HTML 页面教程
  • Android详解——ConstraintLayout约束布局
  • qlib优缺点
  • 【进阶编程】MVC和MVVM实现前后端分离的实现
  • Vue3 重置ref或者reactive属性值
  • WPF 关于界面UI菜单权限(或者任意控件的显示权限)的简单管理--只是简单简单简单简单
  • BigBlueButton视频会议 vs 钉钉视频会议系统的详细对比
  • Ubuntu 20.04 卸载和安装 MySQL8.0
  • 项目实操:windows批处理拉取git库和处理目录、文件
  • [CSP-S 2024] 超速检测 题解
  • 思科CCNA认证都学什么考什么?
  • TCP三次握手,四次挥手
  • 八大设计模式
  • Vue.js实例开发-创建页面用户可以在输入框中输入文本,点击按钮后,页面上会显示一个欢迎消息
  • Certimate:简化 SSL 证书管理的开源工具
  • [python SQLAlchemy数据库操作入门]-12.直接执行 SQL 语句处理股票数据
  • 图书馆管理系统(四)基于jquery、ajax--完结篇
  • x-cmd mod x webtop - 在 Docker 轻松运行多款 Linux 桌面,支持中文,浏览器访问!
  • 中企出海-德国会计准则和IFRS间的差异
  • 京准电钟:电厂自控NTP时间同步服务器技术方案
  • YOLOv8全解析:高效、精准的目标检测新时代——创新架构与性能提升
  • MySQL怎么导出数据库数据
  • Redis 到 Redis 数据迁移同步
  • 指令v-on 调用传参
  • leetcode:3285. 找到稳定山的下标(python3解法)
  • pdf文件中的表格无损提取方案(pdf转Excel),非OCR