前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Linux信号

Linux信号

作者头像
始终学不会
发布于 2023-10-17 00:24:44
发布于 2023-10-17 00:24:44
22900
代码可运行
举报
文章被收录于专栏:小杰的学习本小杰的学习本
运行总次数:0
代码可运行

一.信号基础

生活中

在生活中也有诸多信号,这些信号通常不是由我们发起的,而是我们接收以后对对应的信号做处理;最常见的莫过于红绿灯了,当红绿灯发出信号时(红灯,绿灯,黄灯);我们会有对应的行为,比如绿灯我们知道当前可以行走,红灯的时候我们需要等一等。对信号产生以后我们知道该做什么,这是因为我们曾经接受了对于这些信号的教育,知道当这些信号产生以后我们需要做什么。

技术上

信号并不是由某个进程发起的,而是操作系统发给某个进程的,一个进程异常退出,必定收到了操作系统的信号。使用kill -l可以查看全部的信号

其中1-31为普通信号,34-64被称为实时信号 进程PCB中有一个位图结构用于标明该进程是否收到信号(32个比特位使用0/1来区分是否收到信号,0代表没收到),这也就是说发送信号时需要修改进程PCB,而修改PCB的需要只有操作系统有权限。

进程对于信号的处理有三种:1.默认,2.忽略,3.自定义;

但并不是进程一收到信号就马上处理,因为信号是随时产生的(异步),可能当信号来临时进程正在处理着更重要的事情,进程对信号的处理会在合适的时机(内核态返回用户态时);因为不是马上处理的,所以进程要对信号有保存能力

使用man 7 signal可以查看信号的默认处理行为

Term代表是正常退出; Core代表异常退出,可以开启核心转储功能提供错误定位(后文中会讲) lgn代表内核级忽略

可以看到大部分信号的最终处理都是一样的(退出当前进程),系统设置这些信号主要是为了知道导致进程退出的原因是什么。

二.信号的产生

1.使用键盘组合键发送信号(只能给当前正在运行的进程发)

我们可以使用键盘组合键向进程发送信号,比如之前常用的ctrl+c其实是给进程发送二号信号

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

void handler(int signo)
{
    cout<<"捕捉到了信号,编号为:"<<signo<<endl;
    exit(1);
}

int main()
{
    signal(2,handler);
    while(true)
    {
        cout<<"I am a process,my pid is:"<<getpid()<<endl;
        sleep(1);
    }
    return 0;
}
信号捕捉

上述代码中的signal是一个系统调用,用来捕捉信号,给信号设置自定义处理方式的;它的第一个参数是你要捕捉的信号编号,第二个参数是一个函数指针,代表你要自定义的方法。

在上述代码中,虽然我对2号信号做了捕捉但是我在自定义方法中仍然选择让进程退出了,如果你的自定义方法中不让该进程退出,那么进程收到该信号后就不会再终止

将上述代码改成下面这样,无论是使用ctrl+c还是使用kill -2都无法让该进程终止

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

void handler(int signo)
{
    cout<<"捕捉到了信号,编号为:"<<signo<<endl;
    //exit(1);
}

int main()
{
    signal(2,handler);
    while(true)
    {
        cout<<"I am a process,my pid is:"<<getpid()<<endl;
        sleep(1);
    }
    return 0;
}

那如果我们使用signal将所有的信号都捕捉起来,是否代表该进程无法再被杀死了呢?

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

void handler(int signo)
{
    cout<<"捕捉到了信号,编号为:"<<signo<<endl;
    //exit(1);
}

int main()
{
    for(int signo=1;signo<=31;signo++)
    {
        signal(signo,handler);
    }
    while(true)
    {
        cout<<"I am a process,my pid is:"<<getpid()<<endl;
        sleep(1);
    }
    return 0;
}

看起来该进程似乎已经无法被信号杀死了,那岂不是说明只要一个进程把所有的信号都捕捉起来,那这个进程就可以在系统中肆意妄为?

操作系统不会允许某个进程将所有的信号都捕捉,至少kill -9信号是无法被捕捉的,因为操作系统不相信任何人,它必须要留一手来保护自身的安全


2.使用kill指令(可以向任意进程发送信号)

kill指令我们已经不是第一次使用了,只要有某个进程的pid,那么就可以通过kill向该进程发送信号,终止进程,kill指令其实是通过kill()系统调用实现的,这里就模拟实现以下kill

mysignal.cc

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <string>
void Usage(const std::string& proc)
{
    std::cout<<"Usige:"<<getpid()<< "Signno\n"<<std::endl;
}
 
int main(int argc,char* argv[])//运行main函数时,需要先进行传参
{
    if(argc!=3)//如果传入main函数的参数个数不为3
    {
        Usage(argv[0]);
        exit(1);
    }
    pid_t pid=atoi(argv[1]);//获取第一个命令行参数,作为pid
    int signo=atoi(argv[2]);//获取第二个命令行参数,作为signo
    int n=kill(pid,signo);//需要发送信号的进程/发送几号信号
    if(n==-1)//kill()失败返回-1
    {
        perror("kill");
    }
    while(1)
    {
        std::cout<<getpid()<<std::endl;
        sleep(1);
    }
    return 0;
}

test.cc

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
int main()
{
    while(1)
    {
        std::cout<<"这是一个正在运行的进程"<<getpid()<<std::endl;
        sleep(1);
    }
    return 0;
}
3.使用raise()让进程自己给自己发送信号
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>
#include <cstdio>
#include<cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <string>

//当计数器运行到5时,进程会因3号进程退出
int main(int argc,char* argv[])//运行main函数时,需要先进行传参
{
    int cnt=0;
    while(cnt<=10)
    {
        std::cout<<cnt++<<std::endl;
        sleep(1);
        if(cnt>=5)
        {
            raise(3);
        }
    }
    return 0;
}

raise(signo)其实等价于kill(getpid(),signo),此外虽然raise看起来是进程自己给发送信号,但其实还是操作系统发的,因为发送信号本身就是操作系统对进程所做的。

此外还有一个abort()进程自己给自己发送六号信号


4.硬件异常产生信号

硬件异常产生信号通常是因为软件问题造成的,操作系统通过CPU中的状态寄存器的得知对应硬件的状态,即可向对应进程发送指定的信号。

a.除零引发的异常(SIGRFPE)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>
#include <cstdio>
#include<cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <string>
using namespace std;

void handler(int signo)
{
    cout<<"捕捉到信号,编号为:"<<signo<<endl;
    sleep(1);
}

int main()
{

    signal(8,handler);

    int a=3/0;

    while(true)
    {
        cout<<"当前进程正在运行ing"<<endl;
    }
    return 0;
}

可以看到操作系统一直在给进程发8号信号,可是操作系统是如何得知我有除零错误的呢?

当一个进程被加载进CPU中,才表明该进程正在运行,而CPU中有一套寄存器用于存放进程的上下文,其实除了存放进程上下文的寄存器外,还有寄存器存放了进程PCB的起始地址(这就是为什么CPU可以得知当前正在运行的进程是哪个),以及进程的页表地址,并且CPU中集成了MMU单元,因此将进程的虚拟地址空间转换为物理地址在CPU中就能够完成。

但操作系统之所以能得知当前进程是否有除零错误是因为有一个状态寄存器的存在,状态寄存器中有一个溢出标志位该标志位默认是零(代表正常无溢出),但除零就是除一个无限小的数,得到的结果会无限大所以就会发生溢出,状态寄存器的溢出标志位被置1,操作系统识别到了该行为就给进程发送8号信号(操作系统能识别到该行为,是因为当进程被切换时寄存器的数据也要被替换,因此状态寄存器要被恢复一次,在恢复的时候操作系统就能识别到状态寄存器的信息)。

b.段错误引发的异常(SIGSEVG)

CPU中集成了MMU单元,该单元是实现页表虚拟地址到物理地址之间的转换;一旦你尝试越界访问或者有野指针的问题,能被MMU识别到,然后MMU就会给进程发送信号来终止进程

5.软件问题导致的异常
a.匿名管道的读端关闭,写端还尝试写,操作系统会向写端发送13号SIGPIPE终止写端
b.14号SIGALRM定时器信号

当设定的时间到达时,操作系统向进程发送14号信号终止进程

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int cnt=0;
void handler(int signo)
{
    cout<<"捕捉到信号,编号为:"<<signo <<"当前进程跑的时间为:"<<cnt <<endl;
    //sleep(1);
}

int main()
{


    signal(14,handler);
    alarm(1);
    
    while(1)
    {
        cnt++;
    }
  return 0;
}

这就表明在1秒钟内该while循环被执行了500935048次

任何进程都可以使用闹钟,也就是说操作系统中可能同时存在多个闹钟,因此操作系统需要将闹钟给管理起来(通过先描述再组织的办法)。

三.信号退出时的核心转储

前面提到如果一个信号是Trem则是正常退出,如果是Core则是异常退出,异常信息会写到核心转储中。不过大部分云服务器都是默认关闭了该功能,可以使用ulimit -a来查看核心转储是否被打开

使用ulimit -c+大小可以打开核心转储并设置大小

核心转储的意义就是为了方便调试,当程序异常终止的时候会产生一个文件,再用gdb会该程序调试,则会直接定位到错误

四.信号保存

因为信号不是被立马处理的,所以进程要有对信号保存的能力,这个其实是保存再PCB中的pending位图中

1.基本概念

  1. 实际执行信号的处理动作称为信号递达(Delivery)
  2. 信号从产生到递达之间的状态,称为信号未决(Pending)。
  3. 进程可以选择阻塞 (Block )某个信号。
  4. 被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作.

注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作

2.在内核中的表示

PCB中有两个位图和一个函数指针数组,而位图的下标就代表对应的信号,其中block位图代表的是该信号是否有被阻塞(1代表被阻塞),pending位图代表该信号是否有被递达;而handler是一个函数指针数组,该数组中存放的是函数指针,代表的是该进程对这个信号的处理方法 对于普通信号来说,pending位图中一个时间内只能存放一次同一个信号,如果该信号一直处于未递达的状态,那么即使后续发送了该信号也无法收到

五.信号的处理

因为信号保存在PCB中,但PCB中的数据只有操作系统有权限访问,因此要对信号做处理必须要通过操作系统来实现。

操作系统是一个层状结构,我们做开发也只是在用户层做开发,是没有权限要求操作系统帮我们修改内核中的数据的,这就是为什么一旦我们要访问内核中的数据或者硬件的时候,总是要调用系统调用。

其实调用系统调用之所以能让我们要求操作系统帮我们获得某些数据或者访问硬件,是因为在执行系统调用的时候,首先会执行Int 80这样的汇编代码,陷入内核,让我们从用户态切换到内核态。

在寄存器中有一个CR3寄存器,该寄存器中存放的数据代表的是当前代码的执行权限(0代表内核态,3代表用户态),陷入内核以后操作系统首先会修改CR3的数据。

当然也不用担心陷入内核以后找不到进程的代码,因为有寄存器保存了当前正在执行进程的PCB和用户级页表地址。

再谈地址空间

在前面的博客中只谈论了0–3G的用户级地址空间,现在就再将3–4G的内核级地址空间也拿出来谈论:

1.为什么用户级页表要各自有一份?

首先不同的进程拥有不同的数据,它们代码加载到内存中获得的物理地址也就不同。其次为了保证进程的独立性,每个进程都必须要有各自独立的用户级页表

2.为什么内核级页表所用进程共享一份?

因为操作系统只有一封,被加载到内存中也是独一份,因此没有必须要让每个进程都独立维护一个内核级页表

信号处理全过程

首先因为信号导致的系统调用陷入内核,从用户态切换到内核态,通过寄存器中保存的PCB地址找到PCB,再通过PCB中保存的位图和函数指针来识别信号,如果对于某一个信号的处理方式是自定义处理,那么必须要修改CR3中的权限值,回到用户态去执行自定义方法(因为操作系统不相信任何人,无法知道handler方法中是否有恶意代码); 执行完handler方法以后还需要再回一次内核态,因为进程的上下文数据是由操作系统保存的,无法直接知道之前是从哪一行代码跳转过来的,要想回到之前跳转的代码继续往后面执行,必须要有操作系统的参与。

上述的图也可以简化成下面这样

六.信号集操作函数

1.sigset_t

每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。

因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集,这个类型可以表示每个信号的“有效”或“无效”状态,在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态。


代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <signal.h>
int sigemptyset(sigset_t *set);//将所有比特位清零,表示无有效信号
int sigfillset(sigset_t *set);//使其中所有信号的对应bit置位,表示 该信号集的有效信号包括系统支持的所有信号
int sigaddset (sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);
//注意,在使用sigset_ t类型的变量之前,一定要调 用sigemptyset或sigfillset做初始化,使信号集处于确定的状态

2.sigprocmask

调用sigprocmask可以读取或更改进程的信号屏蔽字(阻塞信号集)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
返回值:若成功则为0,若出错则为-1

如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。

如果set是非空指针,则更改进程的信号屏蔽字,参数how指示如何更改。

如果oset和set都是非空指针,则先将原来的信号 屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。

假设当前的信号屏蔽字为mask,下表说明了how参数的可选值 :

如果调用sigprocmask函数解除了对某个未决信号的阻塞,那么再sigprocmask返回前,该信号可能已经被递达了,一旦信号递达,则说明该进程大概率也要被终止了

3.sigpending
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <signal.h>
int sigpending(sigset_t *set);//set:输出型参数,输出当前进程pending位图
sigending()在成功时返回0,在错误时返回-1。在发生错误时,将 errno 设置。
4.用以上函数写一个代码模块

该代码实现阻塞某一个信号,将这个信号的block位图由0置1,然后接触阻塞,使该信号递达,这个进程直接寄掉

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>
#include<vector>
#include <cstdio>
#include<cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <string>
using namespace std;
#define MAX_SIGNUM 31

static vector<int> sigarr={2};

static void handler(int signo)
{
    cout<<"信号被递达,编号为:"<<signo<<endl;
    //sleep(1);
}

void show_pending(const sigset_t&pending)
{
    for(int i=MAX_SIGNUM;i>=1;i--)
    {
        if(sigismember(&pending,i))
        {
            cout<<"1";
        }
        else
            cout<<"0";

    }
    cout<<endl;
}

int main()
{

    sigset_t pending,block,oblock;

    //为特定的信号更改自定义方法
    for(const auto&sig:sigarr) signal(sig,handler);

    //初始化
    sigemptyset(&pending);
    sigemptyset(&block);
    sigemptyset(&oblock);

    //添加要被屏蔽的信号
    for(const auto &sig :sigarr) sigaddset(&block,sig);
    //  开始屏蔽,设置进内核(进程)
    sigprocmask(SIG_SETMASK, &block, &oblock);
    
 
    // 2. 遍历打印pengding信号集
    int cnt = 10;
    while(true)
    {
        // 初始化
        sigemptyset(&pending);
        // 获取
        sigpending(&pending);
        // 打印
        show_pending(pending);
        
        sleep(1);
        if(cnt-- == 0)
        {
            sigprocmask(SIG_SETMASK, &oblock, &block); // 一旦对特定信号进行解除屏蔽,一般OS要至少立马递达一个信号!
            cout << "恢复对信号的屏蔽,不屏蔽任何信号\n";
        }
    }
return 0;
}

但是由于我对该信号做自定义捕捉了,所以2号信号无法终止该进程了。

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

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

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【Linux】信号的保存
我们也介绍了core term两种默认操作,core在执行信号后会形成一份core文件(默认是关闭的,因为原本core文件的后缀是pid,运行出错后会创建core文件,导致磁盘空间不足),该文件里存储了出错原因,可以再gdb调试时进行使用。
叫我龙翔
2024/06/23
1130
【Linux】信号的保存
Linux进程信号总结
不难看出上面的死循环在代码层面是永远无法结束程序的,那是否还有别的办法?对于死循环来说,最好的方式就是使用Ctrl+C对其进行终止。
咬咬
2024/07/20
820
Linux进程信号总结
Linux信号的保存和处理
每一个信号都有着三张表:block、pending、handler。 两张位图+一张函数指针数组=进程识别信号
南桥
2024/07/26
890
Linux信号的保存和处理
【Linux】进程信号的发送和保存
通过指令man -7 signal查看信号的手册,然后往下翻翻可以看到普通信号发出后对应的操作,以及它们的信号编号,和详细描述信息
s-little-monster
2025/04/01
380
【Linux】进程信号的发送和保存
【Linux】信号>信号产生&&信号处理&&信号保存&&信号详解
SIGINT的默认处理动作是终止进程,SIGQUIT的默认处理动作是终止进程并且Core Dump,我们来验证一下
用户10925563
2024/06/04
2050
【Linux】信号>信号产生&&信号处理&&信号保存&&信号详解
【linux学习指南】详解Linux进程信号保存
如果在进程解除对某信号的阻塞之前这种信号产⽣过多次,将如何处理?POSIX.1允许系统递送该信 号⼀次或多次。Linux是这样实现的:常规信号在递达之前产⽣多次只计⼀次,⽽实时信号在递达之 前产⽣多次可以依次放在⼀个队列⾥。本章不讨论实时信号。
学习起来吧
2024/12/01
1100
【linux学习指南】详解Linux进程信号保存
【Linux】详解信号的保存&&信号屏蔽字的设置
一张为block位图(阻塞位图),也就是一个32位的整形变量,其中取高31位来表示是否阻塞对应的信号,比如说block位图中第0个比特位不用,第1个比特位表示是否阻塞1号信号,第一个比特位为1就表示阻塞1号信号,为0就表示不阻塞1号信号,依次类推,第2到第31个比特位也是同样的道理。
用户10923276
2024/05/03
1720
【Linux】详解信号的保存&&信号屏蔽字的设置
信号初相识:Linux 内核的 “隐形使者”
在 Linux 系统的广袤世界里,信号(Signal)宛如一位神秘的隐形使者,默默地在后台发挥着至关重要的作用。它是一种异步通信机制,如同古代的烽火台,当特定事件发生时,便会燃起 “烽火”,通知进程做出相应的反应。信号可以来自硬件异常,如内存访问错误、除零错误;也能由软件条件触发,像是用户按下特定的按键组合,或者程序主动调用系统函数发送信号 。
用户11396661
2025/02/28
740
【Linux探索学习】第二十八弹——信号(下):信号在内核中的处理及信号捕捉详解
https://blog.csdn.net/2301_80220607/category_12805278.html?spm=1001.2014.3001.5482
GG Bond1
2025/02/05
1030
【Linux探索学习】第二十八弹——信号(下):信号在内核中的处理及信号捕捉详解
【Linux信号】二:未决信号集、阻塞信号集、信号集操作函数
Linux内核的进程控制块PCB是一个结构体task_struct,除了包含进程id、状态、工作目录、用户id、组id、文件描述符表、还包含了信号相关的信息,主要指阻塞信号集和未决信号集。
mindtechnist
2024/08/08
1610
【Linux信号】二:未决信号集、阻塞信号集、信号集操作函数
Linux——进程信号
生活中的信号:红绿灯,手机的来电通知等。 为什么这些是信号呢?因为我们知道这些信号的意义代表着什么。 例如:红绿灯 有人教育过我们,让我们的大脑记住了红绿灯属性对应的行为。 但是,我们就算知道这个信号,也不一定要立刻去处理,因为可能正在做另一间更重要的事情。 所以我们也会有对应的三个动作: 默认动作(看到红灯停),自定义动作(看到红灯不是立刻停下,而而是后退一步或者是其他操作),忽略动作(看到红灯不停)。
有礼貌的灰绅士
2023/05/10
2.8K0
Linux——进程信号
【linux】信号的保存和递达处理
        上节我们了解到了预备(信号是什么,信号的基础知识)再到信号的产生(四种方式)。今天我们了解信号的保存。信号产生,进程不一定立马就去处理,而是等合适的时间去处理,那么在这段时间内,进程就需要保存信号,到了合适时间再去执行!
The sky
2023/10/17
1910
【linux】信号的保存和递达处理
Linux进程信号(产生、保存、处理)/可重入函数概念/volatile理解/SIGCHLD信号
首先区分一下Linux信号跟进程间通信中的信号量,它们的关系就犹如老婆跟老婆饼一样,没有一毛钱的关系。
二肥是只大懒蓝猫
2023/03/30
1.4K0
Linux进程信号(产生、保存、处理)/可重入函数概念/volatile理解/SIGCHLD信号
【Linux】进程信号——信号保存和信号捕捉
信号递达:指 操作系统 将一个信号(Signal)从内核传递到目标进程 的过程。它是 信号处理机制 中的关键步骤。 信号未决:信号从产生到递达之间的状态 信号阻塞 进程或线程可以暂时屏蔽某些信号,使它们在阻塞期间不会递达和处理。一旦解除阻塞,信号会被递达并处理。
用户11305458
2025/03/05
1270
【Linux】进程信号——信号保存和信号捕捉
一文搞懂Linux信号【下】
在观看本博客之前,建议大家先看一文搞懂Linux信号【上】。由于上一篇博客篇幅太长,为了更好的阅读体验,我拆成了两篇博客。那么接下来,在上一篇的基础上,我们继续学习Linux信号部分。本篇我们主要谈论信号保存和信号处理。
破晓的历程
2024/06/24
1320
一文搞懂Linux信号【下】
【Linux】信号知识三把斧——信号的产生、保存和处理
Linux系统提供的让用户(进程)给其他进程发送异步信息的一种方式。(注意信号和信号量这两者没有任何关系!)
用户11316056
2024/10/16
1640
【Linux】信号知识三把斧——信号的产生、保存和处理
【Linux】:进程信号(再谈信号保存和信号捕捉)
🌈 当某个信号的处理函数被调用时,内核自动将当前信号加入进程的信号屏蔽字,当信号处理函数返回时自动恢复原来的信号屏蔽字,这样就保证了在处理某个信号时,如果这种信号再次产生,那么 它会被阻塞到当前处理结束为止
IsLand1314
2024/11/26
1690
【Linux】:进程信号(再谈信号保存和信号捕捉)
【Linux进程信号】Linux信号机制深度解析:保存与处理技巧
🔍前言:在Linux操作系统的广阔天地中,信号机制无疑是一个充满挑战与机遇的领域。信号,作为进程间通信的一种重要方式,不仅承载着丰富的信息,还扮演着进程控制与管理的重要角色。然而,对于许多初学者而言,信号的保存与处理往往是一个难以逾越的障碍
Eternity._
2024/10/15
1720
【Linux进程信号】Linux信号机制深度解析:保存与处理技巧
【Linux】信号的处理
我们说过:信号可能不会被立即处理,而是在合适的时候进行处理。那么这个合适的时候到底是什么时候?!
叫我龙翔
2024/07/09
1050
【Linux】信号的处理
【Linux】进程信号
生活中有很多的信号,比如闹钟、消息提醒、手机铃声,红绿灯。但是人是怎么识别红绿灯的,识别信号的?通过认识产生行为:有人通过教育的手段让我们在大脑中记住了对应的红绿灯属性或者行为;但是当信号到来的时候,我们不一定会马上去处理这个信号:信号可以随时产生(异步),而我们可能会做更重要的事情;信号到来的时候在到信号被处理一定会有时间窗口,必须得记住这个信号;
平凡的人1
2023/10/15
1990
【Linux】进程信号
推荐阅读
相关推荐
【Linux】信号的保存
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验