【Linux操作系统】信号产生

一、信号概念

是什么?

Linux系统提供的让用户(进程)给其他进程发送异步信息的一种方式,注意,信号与信号量没有任何关系。
1、进程可以识别信号并作处理;
2、信号到来时,如果此时有更重要的事情要处理,那么到来的信号要临时保存,即在合适的时候处理;
3、信号的产生是随时的,不能准确预料,所以信号是异步发送的;
4、信号的产生,是由别的进程产生的,当前的进程收到这个信号之前,在做其他的事情,是并发的。

为什么?

因为系统要求进程要有随时响应外部信号的能力,并作出反应。

怎么办?

准备->信号产生->信号保存->信号处理

准备:
1️⃣常见信号:
在这里插入图片描述
数字和名字都可以识别信号,名字其实是宏。从34开始是实时信号。注意,没有32、33信号。

2️⃣信号的处理方式
有:默认、自定义、忽略

默认,就是按原来信号的处理方式进行处理
比如:下面代码死循环用2号信号终止,终止是2号信号的默认处理方式

int main()
{
    while(true)
    {
        cout << "I am acting..., pid: " << getpid()<<endl;
        sleep(1);
    }
    return 0;
}

在这里插入图片描述

自定义是由用户来决定信号的处理方式,与信号的默认处理方式不同。2号信号是终止进程,用户可以让它的处理方式通过函数变成打印一句话和终止进程,终止进程的退出码为100,再把函数给系统调用接口signal。自定义的方式也叫信号的捕捉。
在这里插入图片描述

void handler(int sig)
{
    cout << "I am a sig, sig: " <<sig<<endl;
    exit(0);
}
int main()
{
    signal(2, handler);

    while(true)
    {
        cout << "I am acting..., pid: " << getpid()<<endl;
        sleep(1);
    }
    return 0;
}

在这里插入图片描述

注意:signal调用完,handler方法不会立即被执行,要收到对应的信号才执行;如果没有收到信号,handler方法就不会被调用。

信号忽略,相当于忽略了默认和自定义的处理方法

void handler(int sig)
{
    cout << "I am a sig, sig: " <<sig<<endl;
    exit(100);
}
int main()
{
    //signal(2, handler);
    signal(2, SIG_IGN);

    while(true)
    {
        cout << "I am acting..., pid: " << getpid()<<endl;
        sleep(1);
    }
    return 0;
}

在这里插入图片描述

二、信号产生

信号的产生可以通过kill命令、键盘,还可以通过系统调用接口、软件条件(设置闹钟)、异常产生

1️⃣键盘:比如:ctrl+c
在这里插入图片描述
2️⃣kill系统调用接口——对任意进程发送任意信号

int main(int argc, char* argv[])
{
    if(argc != 3)
    {
        cout << "Usage: " << argv[0] << "-signum pid" << endl;
        exit(1);
    }
    int signum = stoi(argv[1]+1);
    int sigpid = stoi(argv[2]);
    int n = kill(sigpid, signum);
    if(n < 0)
    {
        cout << "kill fail, errno: " << strerror(errno) << endl;
        exit(2);
    }
    return 0;
}

在这里插入图片描述

3️⃣raise——对自己发送任意信号
在这里插入图片描述

int main()
{
    int cnt = 0;
    while(true)
    {
        cout << "cnt: " << cnt++ << endl;
        sleep(1);
        if(cnt == 5)
        {
            cout << "send 9 to caller" <<endl;
            raise(9);
        }
    }
    return 0;
}

在这里插入图片描述

4️⃣设置闹钟
设置一个简单的闹钟,接口alarm,注意,闹钟设置的时间只是什么时候响,但是只响一次。如果函数的参数设置为0,就是取消闹钟

一、

int main()
{
    alarm(1);
    int cnt = 0;
    while(true)
    {
        cout << "cnt: " << cnt++ <<endl;
    }
    return 0;
}

在这里插入图片描述

二、

int cnt = 0;
void handler(int sig)
{
    cout << "sig num: " <<sig << ", cnt: " << cnt << endl;
    exit(0);
}
int main()
{
    signal(SIGALRM, handler);
    alarm(1);
    while(true)
    {
        cnt++;
    }
    return 0;
}

在这里插入图片描述
第二种的cnt比第一种更大,第二种是内存级,较快;第一种是IO级,较慢。

如何让闹钟一直响:在handler方法里面再设置闹钟

int cnt = 0;
void handler(int sig)
{
    cout << "sig num: " <<sig << ", cnt: " << cnt << endl;
    int n = alarm(2);
}
int main()
{
    signal(SIGALRM, handler);
    alarm(1);
    while(true)
    {
        sleep(1);
        cout << "cnt: " << cnt++ <<endl;
    }
    return 0;
}

在这里插入图片描述

5️⃣异常

一、除零

void handler(int sig)
{
    cout << "get a sig: " << sig <<endl;
    exit(0);
}
int main()
{
    signal(SIGFPE, handler);
    int a=10;
    a/=0;
    while(true) sleep(1);

    return 0;
}

在这里插入图片描述

二、野指针

void handler(int sig)
{
    cout << "get a sig: " << sig <<endl;
    exit(0);
}
int main()
{
    signal(SIGSEGV, handler);
    int *p = nullptr;
    *p = 100;
    while(true) sleep(1);

    return 0;
}

在这里插入图片描述

  • 15
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值