【Linux】信号

基本概念

信号是系统响应某个条件产生的事件,进程接收到信号会执行相应的操作。与信号有关的系统调用在“signal.h”头文件中有声明。

系统调用kill()发送信号给进程,进程响应方式有三种:1.默认2.忽略3.自定义,这三种方式用signal()可以改变。

信号的产生

一个事件对应一个信号。

大多数情况为出现了某些异常,产生中断。

信号的值是一个数字,它在程序中定义为一个宏,用数字表示几号信号,常见的有:

#define SIGINT 2 //键盘按下 Ctrl+c 时,会产生该信号
#define SIGKILL 9 //该信号的响应方式不允许改变
#define SIGSEGV 11//访问空指针
#define SIGPIPE 13 //读端关闭的描述符,写端写入时产生,该信号会终止程序
#define SIGTERM 15 //系统 kill 命令默认发送的信号
#define SIGCHLD 17 //子进程结束后,会默认给父进程发送该信号

信号可以用来表示产生了什么错误,使用它便于我们查错

修改信号响应方式

使用signal()修改响应方式如下,其中传入handler的有三种:

1.SIG_IGN忽略

2.SIG_DFL默认

3.自己写的信号处理函数自定义

signal(信号类型,函数指针)

自定义

ctrl+c可以终止当前进程,它的信号是SIGINT,下面来改变一下它的响应使其输出2:

void sig_fun(int sig)
{
    printf("sig=%d\n",sig);
}
int main()
{
    signal(SIGINT,sig_fun);//也可以写signal(2,sig_fun)
    while(1)
    {   
        printf("hello\n");
        sleep(1);
    }   
}

signal是一个设置,执行过了就是设定好了,当遇到这个信号时才以这个设定方式响应。

忽略

默认:SIG_DFL :(void(*)(int)) 0

忽略:SIG_IGN: (void(*)(int)) 1

int main()
{
    signal(SIGINT,SIG_IGN);//SIGINT变FIG_IGN忽略
    while(1)
    {   
        printf("hello\n");
        sleep(1);
    }   
}

多次修改

响应执行的是最后一次设定,如果设置两次,如下,则会忽略信号SIGINT

如果要第一次遇到2信号用自定义方式响应,第二次默认,可以在自定义响应中再重新定义一次

void sig_fun(int sig)
{
    printf("sig=%d\n",sig);
    signal(sig,SIG_DFL);//下一次调用sig_fun时用默认响应
}
int main()
{
    signal(SIGINT,sig_fun);//也可以写signal(2,sig_fun)
    while(1)
    {   
        printf("hello\n");
        sleep(1);
    }   
}

发送信号kill()

kill需要获取pid和信号代号两个参数,返回-1失败,0成功

自己写一个使用kill

int main(int argc ,char*argv[])
{
    if(argc != 3)
    {
        printf("arg err");
        exit(0);
    }
    int sig = 0;
    int pid = 0;
    sscanf(argv[1],"%d",&pid);//把输入的东西以整形的方式传给pid
    sscanf(argv[2],"%d",&sig);

    if(kill(pid,sig)==-1)//用kill
    {
        printf("kill err\n");
    }
    exit(0);
}

运行一下,给上面那个main程序发送信号2

kill -9为强制结束,不能更改

信号实现

信号在PCB中,一开始全是0,32位可以收32个信号,64位收64个。进程什么信号都没有接收,kill发送信号时先根据pid找到那个进程,然后根据信号的值偏移,如果是信号2,则第三位上0变成1如下图。处理完信号后该位置再变回0.

如果短时间内多次发送同一个信号,则可能只响应一次,该位置上1还没变回来。

发送信号处理僵尸进程

子进程结束 内核发送信号SIGCHLD给父进程

默认情况下是忽略了这个信号的,不做任何处理,所以会产生僵尸进程;

可以自定义响应:如果将接收到这个信号后使用wait(),解决僵尸进程。

也可以用忽略,父进程不需要知道返回值;(unix不可行,只有linux系统可以)

void fun(int sig)
{
    wait(NULL);
}
int main()
{
    //signal(SIGCHLD,fun);//自定义处理僵尸进程
    signal(SIGCHLD,SIG_IGN);//忽略子进程返回
    int n=0;
    pid_t pid=fork();
    if(pid==-1)exit(0);
    if(pid==0)
    {
        s="child";
        n=3;
    }
    else
    {
        s = "parent";
        n=7;
    }
    for(int i=0;i<n;i++)
    {
        printf("s=%s\n",s);
        sleep(1);
    }
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

曦樂~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值