前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >【Linux】进程信号

【Linux】进程信号

作者头像
用户11305458
发布2025-03-03 08:33:24
发布2025-03-03 08:33:24
10300
代码可运行
举报
文章被收录于专栏:学习学习
运行总次数:0
代码可运行

进程信号

什么是进程信号?

程信号(Signal) 是一种异步的进程间通信机制,用于通知进程发生了某种事件。

异步事件:不会阻塞当前进程,而是在某个条件满足后触发,并由系统或者回调函数处理的事件。

简单来说:我们用现实中一个很常见的事情来比喻异步事件,异步事件就是当我们在手机上点外卖时,我们不需要一直盯着手机上的点外卖的APP,而可以去做其他事情,当外卖送到的时候,手机上会通知,通知之后我们再决定去不去拿,我们可以选择去处理这个外卖,也可以选择当我们将手上的事完成之后再去取外卖。

处理信号的方式

处理信号的三种方式:默认行为自定义行为忽略

默认行为

每个信号都有自己的默认行为,我们拿一两个举例:

我们拿9号信号为例,9号信号的默认行为就是杀死进程。 我们可以用man命令查看一张表,可以查看每个信号的默认行为:

代码语言:javascript
代码运行次数:0
复制
man 7 signal

这里我截取的了部分图片。

可以查看每个进程的默认行为。

自定义行为

在了解自定义行为之前,我们需要先了解一个系统调用:

signal可以用来捕捉信号。

第二个参数是函数指针,需要我们自己写一个函数传递进来,signal可以用来捕捉信号,然后改变信号的默认行为。 我们用代码来详细说明一下: 前提:首先我们提出一个结论,我们常用的ctrl+c,其实最后会转化为2号信号,系统识别到2号信号后,会将进程杀死,注意:这里杀死进程,只能杀死前台进程,不能杀后台进程,我们先验证,然后写代码

如何将进程变为后台进程:

代码语言:javascript
代码运行次数:0
复制
./signal &

可以看到ctrl+c是结束不了后台进程的,智能用kill -9来杀死这个进程。

代码语言:javascript
代码运行次数:0
复制
#include <iostream>
#include <signal.h>
using namespace std;

void headler(int signo)
{
    cout<<"get a signal"<<signo<<endl;
}

int main()
{
    signal(2,headler);
    while(true)
    {
        cout<<"hello world"<<endl;
        sleep(2);
    }
    return 0;
}

用上面代码来验证ctrl+c是否是2号信号,并未验证signal函数捕捉信号。

可以看见我们ctrl+c的时候,进程不会退出,而是转而输出我们自定义行为的内容。

认识信号

除了上面讲到的ctrl+c表示终止进程,还有组合键也可以终止进程,并且这个组合键转化的信号不是2号信号:

代码语言:javascript
代码运行次数:0
复制
ctrl+\

这个组合键最后会被转化为3号信号,我们来验证一下:

可以看到输出的是3号信号。

假定我们将所有信号捕捉了之后会怎么样呢?

可以看见,无论如何都杀不死进程,那这样这个进程是不是就无法无天了?

9号信号还是可以杀死进程,由于操作系统早已料到这个结果,所以操作系统设置了9号信号是无法捕捉的。 上面讲的都是键盘产生的信号,其实还有系统调用产生信号。

系统调用产生信号

kill可以向指定进程发送指定的信号。

代码语言:javascript
代码运行次数:0
复制
#include <iostream>
#include <signal.h>
#include <sys/types.h>
using namespace std;

void headler(int signo)
{
    cout<<"get a signal "<<signo<<endl;
}
int main()
{
    signal(2,headler);
    kill(getpid(),2);
    while(true){}
    return 0;
}

我们捕捉2号信号,可以看见确实可以向指定进程发送信号。 还有两个两个函数可以发送信号,一个是:raise,一个是abort raise表示无论谁调用raise都会给自己发送信号 abort表示无论谁调用进程都会给自己发送信号终止自己进程。

指令产生信号

没错,kill既是指令也是系统调用,kill也可以产生信号

软件条件产生信号

我们将一个例子,我们之前学的管道,当读端关闭之后,写端继续往管道中写入是非法的,所以系统就会给进进程发送信号将写端关闭。 这里我们讲一个系统调用:

这个系统调用是定时器函数,我们设置一个闹钟,当闹钟到的时候,进程会直接终止,这里我们利用signal,改变14号信号的行为:

代码语言:javascript
代码运行次数:0
复制
#include <iostream>
#include <signal.h>
#include <sys/types.h>
using namespace std;

void headler(int signo)
{
    cout<<"get a signal "<<signo<<endl;
}
int main()
{
    signal(14,headler);
    alarm(1);
    while(true){}
    return 0;
}

可以看见我们通过一个闹钟函数捕捉到了信号,也就是内部软件可以直接产生信号。

异常产生信号

代码语言:javascript
代码运行次数:0
复制
#include <iostream>
#include <signal.h>
#include <sys/types.h>
using namespace std;


int main()
{
    int a = 1/0;
    return 0;
}

可以看见异常也可以产生信号,我们来查一下信号是多少号

可以看见/0产生的8号信号。

总结

进程信号(Signal)是 Linux 中一种重要的 进程间通信异常处理 机制,能够异步通知进程发生特定事件。信号可以来自 用户输入(如 Ctrl+C)、进程间通信kill())、内核事件(如访问非法地址触发 SIGSEGV)或 定时器SIGALRM)。

在实际编程中,我们可以通过 捕获(sigaction())、忽略(SIG_IGN)、阻塞(sigprocmask() 等方式处理信号,以控制进程的行为。例如,使用 SIGCHLD 管理子进程,或使用 SIGUSR1 进行进程间通信。

然而,信号的 异步性 可能导致竞态条件,尤其是在信号处理函数中执行非异步安全操作时。因此,在设计信号处理逻辑时,应该避免使用不可重入函数,并合理利用信号屏蔽集来确保同步执行。

掌握进程信号的机制,不仅有助于编写更健壮的 Linux 应用程序,还能在 系统编程、进程控制、故障诊断 等方面提供强有力的工具。希望本文能帮助你更好地理解 Linux 进程信号的原理及应用!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-03-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 进程信号
    • 什么是进程信号?
    • 处理信号的方式
      • 默认行为
      • 自定义行为
    • 认识信号
    • 系统调用产生信号
    • 指令产生信号
    • 软件条件产生信号
    • 异常产生信号
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档