从零开始UNIX环境高级编程(10):信号

0. 思维导图

从零开始UNIX环境高级编程(10):信号_第1张图片
信号

1. 信号概念


1.1 信号的名字

每个信号都有一个名字,这些名字以SIG开头。Linux将这些信号定义在/usr/include/bits/signum.h中。

/* Signals.  */
#define SIGIGHUP      1   /* Hangup (POSIX).  */
#define SIGINT      2   /* Interrupt (ANSI).  */
#define SIGQUIT     3   /* Quit (POSIX).  */
#define SIGILL      4   /* Illegal instruction (ANSI).  */
#define SIGTRAP     5   /* Trace trap (POSIX).  */
#define SIGABRT     6   /* Abort (ANSI).  */
#define SIGIOT      6   /* IOT trap (4.2 BSD).  */
#define SIGBUS      7   /* BUS error (4.2 BSD).  */
#define SIGFPE      8   /* Floating-point exception (ANSI).  */
#define SIGKILL     9   /* Kill, unblockable (POSIX).  */
... ...
... ...
#define SIGSYS      31  /* Bad system call.  */
#define SIGUNUSED   31

1.2 signal函数

使用signal函数,我们可以捕获一个信号

  • 函数原型

    #include 
    
    typedef void (*sighandler_t)(int);
    
    sighandler_t signal(int signum, sighandler_t handler);
    
  • 参数说明

  • signum:信号量,即信号的名字

  • 返回值
    returns the previous value of the signal handler, or SIG_ERR on error.

  • handler
    如果handler是一个函数地址,当收到signum信号时,则调用handler函数,该函数被称为信号处理函数
    如果handler的值是常量SIG_IGN,表示忽略此信号;后面会有一个示例
    如果handler的值是常量SIG_DFL表示按照系统默认动作执行
    SIG_IGN、SIG_DFL也定义在/usr/include/bits/signum.h中。

   /* Fake signal functions.  */
   #define SIG_ERR ((__sighandler_t) -1)       /* Error return.  */
   #define SIG_DFL ((__sighandler_t) 0)        /* Default action.  */
   #define SIG_IGN ((__sighandler_t) 1)        /* Ignore signal.  */

1.3 产生信号的条件

从零开始UNIX环境高级编程(10):信号_第2张图片
产生信号的条件

1.4 处理信号的方式

处理信号的方式一共有3种,分别是:捕捉信号忽略此信号执行系统默认动作

1. 捕捉信号

使用signal函数可以捕获信号

  • 示例代码

当捕获当SIGINT信号时,就调用sig_int函数,打印received SIGINT

#include "apue.h"

void sig_int()
{
    printf("received SIGINT\n");
    return;
}

int main(int argc, char const *argv[])
{
    signal(SIGINT, sig_int);
    for (; ;)
        sleep(1);
    return 0;
}
  • 输出结果
从零开始UNIX环境高级编程(10):信号_第3张图片
捕捉信号

2. 忽略此信号

将signal函数的handler参数赋值为SIG_IGN,就可以实现忽略此信号的功能

  • 示例代码

当用户输出ctrl+c时,产生的SIGINT信号会被忽略

#include "apue.h"

int main(int argc, char const *argv[])
{
    signal(SIGINT, SIG_IGN);
    for (; ;)
        sleep(1);
    return 0;
}
  • 输出结果
从零开始UNIX环境高级编程(10):信号_第4张图片
signal

3. 执行系统默认动作

如果没对信号进行捕获或者忽略,那么在收到信号时,进行将执行系统默认动作。使用man kill可以查看每个信号对应的系统执行默认动作。例如,SIGINT的默认Action为exit,即如果进程收到该信号,默认执行进程退出。

从零开始UNIX环境高级编程(10):信号_第5张图片
man kill

除了exit,系统的支持的action还有ignore(忽略)stop(停止)core。其中core指的是进程收到信号后会产生一个Core Dump File

Core Dump File是否生成由Core文件大小决定,Linux中默认的Core文件大小设置为零,也就是不生成Core Dump File。想要生成Core Dump File,需要通过命令 ulimit -c unlimited 来设置Core文件大小为无限制

root@ubuntu:/home/ckt/work/unix/code/chapter10# ulimit -c unlimited

通过命令**echo "core-%e-%p-%t" > /proc/sys/kernel/core_pattern **可以设置Core Dump File的命令规则

root@ubuntu:/home/ckt/work/unix/code/chapter10# echo "core-%e-%p-%t" > /proc/sys/kernel/core_pattern

运行上面例子中的signal程序,让它在后台运行,使用kill命令发送SIGSEGV信号给该进程,由于SIGSEGV的默认action为core,该进程在收到SIGSEGV信号后会生成一个Core Dump File

root@ubuntu:/home/ckt/work/unix/code/chapter10# ./signal &
[1] 16613
root@ubuntu:/home/ckt/work/unix/code/chapter10# jobs
[1]+  Running                 ./signal &
root@ubuntu:/home/ckt/work/unix/code/chapter10# kill -11 %1
root@ubuntu:/home/ckt/work/unix/code/chapter10# 
[1]+  Segmentation fault      (core dumped) ./signal
root@ubuntu:/home/ckt/work/unix/code/chapter10# ls -l | grep core
-rw------- 1 root root 253952 Apr 18 01:53 core-signal-16613-1492505601

下面以一段代码演示由于进程没有捕获SIGINT,再收到该信号后,进程会执行退出

  • 示例代码
#include "apue.h"

int main(int argc, char const *argv[])
{
    for (; ;)
        sleep(1);
    return 0;
}
  • 输出结果
从零开始UNIX环境高级编程(10):信号_第6张图片
没有捕获**SIGINT**,执行系统默认动作

待续

... ...


参考

  • jobs 命令
  • Linux中生成 Core Dump 文件的方法
  • 详谈 UNIX 环境进程异常退出

你可能感兴趣的:(从零开始UNIX环境高级编程(10):信号)