Linux进程信号(上)

目录

一:信号引入

二:信号保存方式

三:信号处理方式

四:查看Linux信号

五:信号捕捉

六:信号产生

一:终端按键产生信号 

二:系统函数产生信号

2.1:kill()

2.2:raise()

2.3:abort() 

三:软件条件产生信号


一:信号引入

生活中有很多信号:红绿灯,闹钟,警灯,外卖员的电话等等。把这些称作信号是有一个共同特点:接收到这些信号后,会执行一个动作。因此我们引出Linux中的信号。

1:为什么会执行这个动作?说明我们(进程)可以识别这个信号。

2:我们识别到信号,能够做出对应的动作。说明我们(进程)可以处理信号。

3:当我们在打游戏时接收到外卖员电话,我们可能会说等一等,我过会去拿。这说明信号可能随时产生,我们(进程)会记录信号。

4:在我们让外卖员等一等的时候,我们仍然在干别的事情,说明我们(进程)在识别信号---处理信号之间有个时间窗口。

5:整个拿外卖的过程是异步的,也就是说进程信号的产生是异步的。(因为进程执行到任何地方,都有可能接收SIGINT而终止)

二:信号保存方式

在系统中一定会产生多个进程,对多个进程发信号,就要把这么多信号保存起来,因此采用先描述再组织的方法。

Linux中采用位图,用0和1表示信号的有无,通过不同的比特位为1表示不同的信号。

所谓的发信号就是写入信号,修改特定进程的位图中对应的比特位为1。而这种task_struct数据内核结构,只能由OS来修改。无论有多少信号写入进程,最后都是由OS来完成最后的发送过程。

三:信号处理方式

  • 默认动作
  • 忽略信号
  • 用户自定义动作

四:查看Linux信号

之前我们学进程章节有用过kill -9来杀死一个进程,现在可以用kill -l查看信号。

共61个信号,没有0信号,32信号,33信号。

1--31信号为普通信号。

34-64信号为实时信号。

通过man 7 signal查看详细的信号信息:

 

 

Term:正常退出

Core:异常退出,可以使用核心转储功能定位错误(core dump)

Lgn:内核级忽略 

2)SIGINT  终止信号,即键盘输入ctrl+c
3)SIGQUIT 终止信号,即键盘输入ctrl+\
6)SIGABRT 终止信号  调用abort即可收到该信号
8)SIGFPE  终止信号  除0错误即可收到该信号
11)SIGSEGV 终止信号 段错误即可收到该信号
13)SIGPIPE 终止信号 匿名管道读端关闭,写端即可收到该信号
14)SIGALRM 终止信号 alarm()函数(定时器)
17)SIGCHLD 内核级忽略信号 子进程退出时会向父进程发送该信号
18)SIGURG 继续进程(进程切换至后台运行,通过9号信号杀掉)
19)SIGSTOP 暂停进程

可以发现,很多信号的功能(Action)是一样的,为什么这么多信号,功能却要设置一样,就定义几个信号不就行了吗?这是因为不同的信号对应不同的事件,而不同的事件处理结果可以是一样的。

五:信号捕捉

man signal

SIGNAL(2) 
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

首先要对void进行typedef,定义为参数为int的函数指针。 

参数一:需要捕捉的信号的编号(1-64)

参数二:对捕捉到的信号设置自定义动作

handler设置为SIG_DFL表示信号默认处理方式,SIG_ING设置为忽略处理

 

#include<signal.h>
#include<iostream>
#include<unistd.h>
typedef void (*sighandler_t)(int);
void handler(int signo)
{
    std::cout<<"进程捕捉到信号并执行自定义处理动作"<<std::endl;
}
int main()
{
    signal(2,handler);
    while(1)
    {
        std::cout<<getpid()<<std::endl;
        sleep(1);
    }
    return 0;
}

 将二号信号的动作更改为我们用户自定义的动作,而二号信号就是ctrl +c,或者kill -2,当输入ctrl+c的时候没有终止进程,而是执行我们的动作。

如果写一个循环,把每个信号都捕捉呢?那肯定不行,在Linux中,9号始终是杀死进程,19号是暂停进程。

注意:当用了signal函数后,handler并没有执行!

六:信号产生

一:终端按键产生信号 

SIGINT默认处理动作是终止进程
SIGQUIT默认处理动作是终止进程并且Core Dump

这个知识点和下篇的核心转储一起讲。

注意:ctrl+c默认动作只能杀掉前台进程

运行一个进程的时候如果+&,就会后台运行。 这里是杀不掉的,只能用kill -9

二:系统函数产生信号

2.1:kill()

man 2 kill

 

 参数1是进程pid,参数2是信号编号

成功返回0,失败返回-1

我们借用kill()来仿写一个命令行的kill命令

mykill.cc 

void usage(const std::string s)
{
    std::cout<<"\t usage: \n\t";
    std::cout<<s<<"-信号编号 进程pid"<<std::endl;
}
int main(int argc,char* argv[])
{
    if(argc != 3)
    {
        usage(argv[0]);
        exit(1);
    }
    pid_t pid = atoi(argv[2]);
    int signo = atoi(argv[1]);
    int n = kill(pid,signo);
    if(n!=0)
    {
        std::cerr<<errno<<":"<<strerror(errno)<<std::endl;
        exit(2);
    }
    return 0;
}

loop.cc

int main()
{
    while(true)
    {
        std::cout<<"我是一个进程 pid :"<<getpid()<<std::endl;
        sleep(1);
    }
    return 0;
}

argc和argv在环境变量章节有讲到(后面补),是命令行的参数个数,和命令行分割后的结果 ,需要使用c语言的atoi把命令行参数变为整形的(pid和signo)。

2.2:raise()

 参数就是信号编号

给当前进程发送信号。

成功返回0,错误返回-1

2.3:abort() 

让当前信号接收到信号而终止。因为有exit,所以abort很少用,abort函数总是会成功的所以没有返回值。 

三:软件条件产生信号

alarm是14号信号

#include <unistd.h>
unsigned int alarm(unsigned int seconds);
调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发SIGALRM信号, 该信号的默认处理动
作是终止当前进程。

可以通过alarm,来查看一个机器的算力。如:

static int n = 0;
void myhandler(int signo)
{
    std::cout<<"n = :"<<n<<std::endl;
    exit(0);
}
int main()
{
    signal(SIGALRM,myhandler);
    alarm(1);
    while(1)
    {
        ++n;
    }
    return 0; 
}

捕捉alarm的信号改为用户自定义信号。否则默认动作退出进程不知道n是多少。

 可以看到n是4亿多。

 再看alarm函数,返回值是上一个闹钟剩下的时间,验证一下:

void myhandler(int signo)
{
    int n = alarm(10);
    std::cout<<"last remain time: "<<n<<std::endl;
}
int main()
{
    std::cout<<getpid()<<std::endl;
    signal(SIGALRM,myhandler);
    alarm(10);
    // while(1)
    // {
    //     ++n;
    // }
    while(true)
    {
        sleep(1);
    }
    return 0; 
}

 

 本节讲完,坐等下篇!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不熬夜不抽烟不喝酒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值