linux——信号(signal)

https://www.jianshu.com/p/f445bfeea40a

信号概述:

对于 Linux来说,实际信号是软中断,许多重要的程序都需要处理信号。信号,为 Linux 提供了一种处理异步事件的方法。比如,终端用户输入了 ctrl+c 来中断程序,会通过信号机制停止一个程序。

信号概述

  1. 信号的名字和编号:
    每个信号都有一个名字和编号,这些名字都以“SIG”开头,例如“SIGIO ”、“SIGCHLD”等等。
    信号定义在signal.h头文件中,信号名都定义为正整数。
    具体的信号名称可以使用kill -l来查看信号的名字以及序号,信号是从1开始编号的,不存在0号信号。kill对于信号0又特殊的应用。

  • 忽略信号,大多数信号可以使用这个方式来处理,但是有两种信号不能被忽略(分别是 SIGKILLSIGSTOP)。因为他们向内核和超级用户提供了进程终止和停止的可靠方法,如果忽略了,那么这个进程就变成了没人能管理的的进程,显然是内核设计者不希望看到的场景
  • 捕捉信号,需要告诉内核,用户希望如何处理某一种信号,说白了就是写一个信号处理函数,然后将这个函数告诉内核。当该信号产生时,由内核来调用用户自定义的函数,以此来实现某种信号的处理。
  • 系统默认动作,对于每个信号来说,系统都对应由默认的处理动作,当发生了该信号,系统会自动执行。不过,对系统来说,大部分的处理方式都比较粗暴,就是直接杀死该进程。
    具体的信号默认动作可以使用man 7 signal来查看系统的具体定义。在此,我就不详细展开了,需要查看的,可以自行查看。也可以参考 《UNIX 环境高级编程(第三部)》的 P251——P256中间对于每个信号有详细的说明

了解了信号的概述,那么,信号是如何来使用呢?

其实对于常用的 kill 命令就是一个发送信号的工具,kill 9 PID来杀死进程。比如,我在后台运行了一个 top 工具,通过 ps 命令可以查看他的 PID,通过 kill 9 来发送了一个终止进程的信号来结束了 top 进程。如果查看信号编号和名称,可以发现9对应的是 9) SIGKILL,正是杀死该进程的信号。而以下的执行过程实际也就是执行了9号信号的默认动作——杀死进程

信号处理发送函数

信号发送函数也不止一个,同样分为入门版和高级版
1.入门版:kill
2.高级版:sigqueue

信号注册函数——入门版

在正式开始了解这两个函数之前,可以先来思考一下,处理中断都需要处理什么问题。
按照我们之前思路来看,可以发送的信号类型是多种多样的,每种信号的处理可能不一定相同,那么,我们肯定需要知道到底发生了什么信号。
另外,虽然我们知道了系统发出来的是哪种信号,但是还有一点也很重要,就是系统产生了一个信号,是由谁来响应?
如果系统通过 ctrl+c 产生了一个 SIGINT(中断信号),显然不是所有程序同时结束,那么,信号一定需要有一个接收者。对于处理信号的程序来说,接收者就是自己

捕捉信号示例:

键盘按下ctrl+c无法结束当前进程:

#include<signal.h>
#include<stdio.h>
//typedef void (*sighandler_t)(int);
//sighandler_t signal(int signum, sighandler_t handler);
void handler(int sigum)
{
        printf("get signum%d\n",sigum);
        printf("never quit\n");
}
int main()
{
        signal(SIGINT,handler); //完成注册信号。SIGINT为ctrl+c编码为2,触发ctrl+c后会调用handler,e而不是系统默认的结束程序信号。
        while(1);
        return 0;
}

kill的使用:

#include<signal.h>
#include<stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>

int main(char argc,char **argv) //代表程序要传参
{
        int signum;
        int pid;

        signum = atoi(argv[1]); //将signumatoi转换成10进制
        pid =atoi(argv[2]);  //将pid 转换成10进制

        printf("num = %d,pid = %d\n",signum,pid);
        kill(pid,signum); //调用kill指令发送信号
        printf("send signum ok\n");
        return 0;
}

signalaction:

signal.demo1:

#include<stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
void handler(int signum,siginfo_t *info,void *context)
{
        printf("get message %d\n",signum);
        if(context != NULL)
        {
                printf("get data = %d\n",info->si_int);
                printf("get data = %d\n",info->si_value.sival_int);
                printf("from:%d\n",info->si_pid);
        }
}
int main()
{
        struct sigaction act;
        printf("pid = %d\n",getpid());

        act.sa_sigaction =handler;
        act.sa_flags = SA_SIGINFO;//be able to get message;

        sigaction(SIGUSR1,&act,NULL);
        while(1);
        return 0;
}

send.c

#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
#include <sys/types.h>
#include <unistd.h>

// int sigqueue(pid_t pid, int sig, const union sigval value);

int main(int argc,char **argv)
{
        int signum;
        int pid;

        signum = atoi(argv[1]);
        pid    = atoi(argv[2]);
        union sigval value;
        value.sival_int = 100;
        sigqueue(pid,signum,value);
        printf("%d done\n",getpid());

        return 0;
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值