linux进程信号

什么是Linux信号?


本质是一种通知机制,用户 or 操作系统通过发送一定的信号,通知进程,某些事件已经发生,你可以在后续进行处理

 singal

结合进程,信号结论


a.进程要处理信号,必须具备信号“识别”的能力(看到+处理动作)
b.凭什么进程能够“识别”信号呢?程!
c信号产生是随机的,进程可能正在忙自己的事情,所以,信号的后续处理,可能不是立即处理的!
d.信号会临时的记录下对应的信号,方便后续进行处理
e.在什么时候处理呢?合适的时候
g.一般而言,信号的产生相对于进程而言是异步的

产生信号

信号的捕捉

调用signal函数,输入对应的信号码,就可以捕捉到对应的内容。

signal制作

信号如何产生

ctrl+c本质就是通过健盘組合键向目标进程发送2号信号,然后在执行的进程就退出了。

信号处理的常见方式:

a.默认(进程自带的,程序员写好的逻辑) 
b.忽略(也是信号处理的一种方式)
c.自定义动作(捕捉信号)

 如何理解组合键变成信号呢?

键盘的工作方式是通过:中断方式进行的,当然也能够识别组合键,ctrl+c
OS解释组合键->查找进程列表->前台运行的进程->OS写入对应的信号到进程内部的位图结构中!

如何理解信号被进程保存呢?

a.什么信号?
b.是否产生?
进程PCB内部保存了信号位图字段必须具有保存信号的相关数据结构(位图,unisgned int)

如何理解信号发送的本质?

信号位图是在task_struct -> task_struct内核数据结构->OS

核心转储

在进程等待的waitpid中的status参数第七位有个叫core dump的标志位就叫核心转储,当进程发生错误或者收到信号,那么就会有一个core的文件用于调试。

ulimit

ulimit -a可以查看是否开启核心转储,一般在云服务器上是关闭的

ulimit -c unlimited不限制文件大小

打开核心转储

终止进程后看到core文件

 错误地方会立即标注

abort

使进程终止运行

验证服务器算力alarm

说明了io的速度是远远低于cpu的

为什么生产环境一般都是要关闭core

有可能会产生大量的代码,占用存储空间

系统调用接口

如何理解?用户调用系统接口->执行OS对应的系统调用代码->OS提取参数,或者设置特定的数值->OS向目标进程写信号->修改对应进程的信号标记位->进程后会处理信号->执行对应的处理动作!

由软件条件产生信号

管道中写端关闭写,读端关闭读

硬件异常产生信号

如何理解除0呢?
1.进行计算的是CPU,这个硬件
2.CPU内部是有寄存器的,状态寄存器(位图),有对应的状态标记位,溢出标记位,OS会自动进行计算完毕之后的检测!如果溢出标记位是1,OS里面识别到有溢出问题,立即只要找到当前谁在运行提取PID,OS完成信号发送的过程,进程会在合适的时候,进行处理
3.一旦出现硬件异常,进程一定会退出吗?不一定!一般默认是退出,但是我们即便不退出,我们也做不了什么
4. 为什么会死循环?寄存器中的异常一直没有被解决!


如何理解野指针或者越界问题?
1.都必须通过地址,找到目标位置
2. 我们语言上面的地址,全部都是虚拟地址
3. 将虚拟地址转成物理地址
4.页泰+MMU(Memory Manager Unit, 硬件!!)
5.野指针,越界-》非法地址-》MIMU转化的时候,一定会报错!

信号产生

task_struct中一共有三张和信号产生的表有关,pending、block和handler,panding表示未达代表了有无收到了信号,block表示是否屏蔽该信号,handler表示处理方法,实际上就是个回调函数。block 位图,结构和pending一模一样位图中的内容,代表的含义是对应的信号是否被阻塞

sigset_t

sigset_t--- 不允许用户自己进行位操作---0S 给我们提供了对应的操作位图的方法

sigset_t---user是可以直接使用该类型—-和用内置类型 && 自定义类型 沒有任何差別

sigset t---定需要对应的系统接口,来完成对应的功能,其中系統接口需要的参数,可能就包含了sigset t 定义的变量或者对象

#include<signal.h>

sigpending(sigset_t *set);

获取当前调用进程的pending信号集

int sigemptyset (sigset_t *set);

清空表中内容


int sigfillset(sigset_t *set);

将表中内容置1


int sigaddset (sigset_t *set, int signo);

将signal添加到表中,常用于block中添加屏蔽关键字

int sigdelset (sigset_t *set, int signo);

将signal从表中删除,常用于block中删除屏蔽关键字

int sigismember (const sigset _t *set, int signo);

可以用于输出该表中的成员

int sigprocmask(int how,const sigset_t *set,sigset_t *oldset)

其中how填以下图标的内容,oldset是输出型参数,返回老的set,如果不需要可以填nullptr

例1

捕捉信号,从1-31,其中管理员信号9不能被捕捉。

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

void handler(int signum){
    cout<<"catching a signal now:"<<signum<<endl;
}
int main(){
    cout<<getpid()<<endl;
    for(int i=1;i<=31;i++){
        signal(i,handler);
    }
    while(true)sleep(1);
}

例2

输出信号集,从1-31,,block2号信号,等待2号被捕捉。

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

void showsigpeding(sigset_t pending){
    for(int i=1;i<31;i++){
        if(sigismember(&pending,i)){
            cout<<"1";
        }else{
            cout<<"0";
        }
        
    }
    cout<<endl;
}
int main(){

    sigset_t bset,obset;
    sigset_t pending;

    sigemptyset(&bset);
    sigemptyset(&obset);
    sigemptyset(&pending);

    sigaddset(&bset,2);
    int n=sigprocmask(SIG_BLOCK,&bset,&obset);
    assert(n==0);
    cout<<"sigprocmask success "<<"n:"<<n<<" "<<getpid()<<endl;

    while(true){
        sigpending(&pending);
        showsigpeding(pending);
    sleep(1);
    }

}

信号产生之后,信号可能无法被立即处理,在合适的时候被处理,那么什么时候合适呢?

在内核态中,内核态返回用户态的时候进行检测

为什么会陷入内核态?

因为用户态会进行系统调用,缺陷陷阱异常等情况

用户态->内核态执行流程

用户态是一个受管控的状态,内核态是一个操作系统执行自己代码的一个状态,具有非常高的优先级。

cpu寄存器有两套,一套可见,平常所见ax,bx都是可见。一套不可见,表示cpu寄存器状态的,比如CR3表示当前cpu执行权限,1为内核,3为用户态。

捕捉信号

首先在用户态中因为一些系统中断、异常进行内核,可能是open之类的系统调用函数,进入内核中处理异常准备回用户模式前处理递送的信号,如果发现pending表为1,block表为0,那么就会去回调函数中的handler函数,handler函数处理完再返回用户态执行上次被中断的地方的语句,执行完毕再返回用户态执行main函数,执行其他流程。

sigaction

捕捉信号后10秒再重新清空捕捉

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

void showpending(sigset_t *pending ){
    for(int i=1;i<=31;i++){
        if(sigismember(pending,i))cout<<1;
        else{
            cout<<0;
        }
    }
    cout<<endl;

}
void handler(int signum)
{
cout<<"获取了一个信号:"<< signum << endl;
cout<<"获取了一个信号:"<< signum << endl;
cout<<"获取了一个信号:"<< signum << endl;
cout<<"获取了一个信号:"<< signum << endl;
sigset_t pending;
int c=10;
while(true){
    sigpending(&pending);
    showpending(&pending);
c--;
    if(!c){
        break;
    }
    sleep(1);


}

}

int main(){
 signal(2,SIG_IGN);
// signal(3,SIG_IGN);
    // 内核数据类型,用户栈定义的
    struct sigaction act, oact;
act.sa_flags = 0;
sigemptyset (&act.sa_mask);
act.sa_handler = handler;

// 设置进当前调用进程的pcb中
sigaction(2, &act, &oact);
cout<<"default action: "<<(int)(oact.sa_handler)<<endl;
while(true) sleep(1);
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值