linux信号

本文深入探讨了Linux系统下的信号机制,包括信号的概念、信号的产生方式、信号的阻塞与递达过程,以及如何利用信号集操作函数进行信号处理。通过实例代码展示了信号屏蔽与解除的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.我们首先要理解什么叫linux下的信号
比如:用户输入命令,在shell下启动一个前台进程;用户按下Ctrl+c等各种组合键产生一个硬件中断等等
2.在linux下进程分为前台进程和后台进程下面通过一段代码我们了解一下他们

#include<stdio.h>
#include<stdlib.h>

int main()
{
    while(1){
        ;
    }
    return 0;
}

前台进程不能在输入命令
通过ps aux|grep mytest 命令可以参看该前台程序的状态显示为R+


接下来我们看下将该程序设置为后台程序
命令为./mytest &
当程序设置为后台时,我们还可以进行别的命名操作
这里写图片描述
当我们用命令ps aux|grep mytest 查看进程状态时,可以看出
后台的进程为R
这里写图片描述
3.linux为我们一共提供了62个信号,其中1-31是普通信号,34-64为实时信号。我们重点关注的是1-31号信号。
这里写图片描述
4.信号产生的三种方式
1.通过终端按键产生信号
2.调用系统函数向进程发送信号
3.由软条件产生信号
5.阻塞信号
我们先明白几个概念
信号递达:实际执⾏信号的处理动作称为信号递
达(Delivery),
信号未决:信号从产⽣到递达之间的状态,称为信号未决(Pending)。
进程可以选择阻塞
(Block )某个信号。被阻塞的信号产⽣时将保持在未决状态,直到进程解除对此信号的阻塞,
才 执⾏递达的动作。注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,⽽忽略是在递
达之后 可选的⼀种处理动作。
由上面我们知道信号有62个,那么我们是怎么在内核表示这62个信号那?设计者用位图巧妙的表示了这62个信号的状态,用下标表示几号信号,用内容表示信号的不同状态。并且他们是在PCB中存储着,下面我用图片介绍下信号在内核中的存储情况
1这里写图片描述
每个信号都有两个标志位分别表⽰阻塞(block)和未决(pending),还有⼀个函数指针表⽰处理
动作。信号产⽣时,内核在进程控制块中设置该信号的未决标志,直到信号递达才清除该标
志。
5.下面是信号集操作函数

#include<signal.h>
//初始化set所指向的信号集,使其对应位,及不包含任何有效信号
int sigemptyset(sigset_t *set)
//初始化set所指向的信号集,使其所有信号对应位置位
int sigfillset(sigset_t *set)
//在信号集中添加某种有效信号
int sigaddset(sigset_t *set,int signo)
 int sigdelset(sigset_t *set,int signo)
//上面四个信号操作函数都是成功返回0,出错返回-1.
//初始化sigset_t 类型的变量时,我们一定要调用sigemptyset,sigfillset两个函数。


//判断一个信号集的有效信号是否包含某种信号,它是一个布尔类型
int sigismember(const sigset_t *set,int signo)
//可以读取或更改进程的信号屏蔽字,成功0,出错-1
int sigprocmask(int how,sigset_t *set,sigset_t *oset)
//读取当前进程的未决信号集合,通过参数set传出
int sigpending(sigset_t *set))

我们看下sigprocmask的三个参数:第一个参数

  1. SIG_BLOCK set包含了我们呢希望添加到当前信号屏蔽字的信号
  2. SIG_UNBLOCK set包含了我们希望从当前信号屏蔽字中解除阻塞的信号
  3. SIG_SETMASK 设置当前信号屏蔽字为set所指的值
    第二个参数:如果是非空指针,更改进程的信号屏蔽字
    第三个参数:如果是非空指针,则读取进程的当前信号屏蔽字,通过参数传出
    如果二,三参数都为非空指针,先将原来的信号屏蔽字备份到oset,然后根据set和how参数更改信号屏蔽字
    6下面我们通过代码来编写进程信号三张表相关的代码
    并且测试信号屏蔽与解除并递达
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>

void showpending(sigset_t *pending){
    int i=1;
    for(i;i<32;i++){
        if(sigismember(pending,i)){
            printf("1");
        }else{
            printf("0");
        }
    }
    printf("\n");
}
void handle(int sig){
    printf("get a sig %d\n",sig);
}

int main()
{
    sigset_t newset,oldset,pending;//在使用sigset_t类型时,一定要用下面函数初始化
    sigemptyset(&newset);
    signal(2,handle);
    sigemptyset(&oldset);//使所有信号设置位0
    sigaddset(&newset,2);//设置2号信号
    sigprocmask(SIG_SETMASK,&newset,&oldset);
    int count=0;

    while(1){
        sigpending(&pending);//读取当前未决信号
        showpending(&pending);//显示当前信号集
        sleep(1);
        if(count++==10){
            printf("recover\n");
            sigprocmask(SIG_SETMASK,&oldset,NULL);
        }
    }

    return 0;
}

我们在键盘输入Ctrl+c程序捕捉到2号信号,打印十次后,我们再次调用了解除屏蔽字函数,可以看出最后显示恢复原来的值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值