博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[单刷APUE系列]第十章——信号[1]
阅读量:5838 次
发布时间:2019-06-18

本文共 7798 字,大约阅读时间需要 25 分钟。

目录

[单刷APUE系列]第十章——信号[1]

信号概念

从前面的文章和实际使用中,大家应该也对信号有一些模糊的认识了。比如,Nginx使用信号来管理进程的启动关闭,UNIX进程信号是经典的操作异步事件机制。在早期,Unix信号是每个实现都不同的,但是随着Unix标准化的进行,标准提出了统一的信号机制模型。除了共有的信号以外,各自的实现还提供了扩展信号,当然,这个不是重点。

在头文件<signal.h>中定义了所有的信号,我们可以通过编辑这个头文件来查看当前Unix实现提供的信号。

#define SIGHUP  1       /* hangup */#define SIGINT  2       /* interrupt */#define SIGQUIT 3       /* quit */#define SIGILL  4       /* illegal instruction (not reset when caught) */#define SIGTRAP 5       /* trace trap (not reset when caught) */#define SIGABRT 6       /* abort() */...

就是这样列出来的,从上面可以看到,信号不存在为0的编号,在最初的几章里,提到过产生信号的条件

  1. 终端按键产生信号,例如:Ctrl+C、Ctrl+\这种形式

  2. 硬件产生信号,比如除以0错误等,都是通过中断通知内核,然后产生信号

  3. 进程调用 kill 函数发送信号,在前面权限部分就提到过,想要发送信号,则所有者权限需要检查或者说有效用户组是root权限

  4. 用户使用 kill 命令,实际上就是调用了 kill 函数

  5. 系统产生的软中断

信号是进程交互和异步事件的方式,由于信号出现是不可知的,所以不能说像检查返回值,检查 errno 一样判断是否有信号,系统提供了一套完善的机制来实现,开发者只需要让进程注册函数来处理信号。

进程收到信号后,可以选择3种方式处理行为:

  1. 忽略信号

  2. 捕捉信号

  3. 执行系统默认行为

下面列出了通常的信号

No    Name         Default Action       Description1     SIGHUP       terminate process    terminal line hangup2     SIGINT       terminate process    interrupt program3     SIGQUIT      create core image    quit program4     SIGILL       create core image    illegal instruction5     SIGTRAP      create core image    trace trap6     SIGABRT      create core image    abort program (formerly SIGIOT)7     SIGEMT       create core image    emulate instruction executed8     SIGFPE       create core image    floating-point exception9     SIGKILL      terminate process    kill program10    SIGBUS       create core image    bus error11    SIGSEGV      create core image    segmentation violation12    SIGSYS       create core image    non-existent system call invoked13    SIGPIPE      terminate process    write on a pipe with no reader14    SIGALRM      terminate process    real-time timer expired15    SIGTERM      terminate process    software termination signal16    SIGURG       discard signal       urgent condition present on socket17    SIGSTOP      stop process         stop (cannot be caught or ignored)18    SIGTSTP      stop process         stop signal generated from keyboard19    SIGCONT      discard signal       continue after stop20    SIGCHLD      discard signal       child status has changed21    SIGTTIN      stop process         background read attempted from control terminal22    SIGTTOU      stop process         background write attempted to control terminal23    SIGIO        discard signal       I/O is possible on a descriptor (see fcntl(2))24    SIGXCPU      terminate process    cpu time limit exceeded (see setrlimit(2))25    SIGXFSZ      terminate process    file size limit exceeded (see setrlimit(2))26    SIGVTALRM    terminate process    virtual time alarm (see setitimer(2))27    SIGPROF      terminate process    profiling timer alarm (see setitimer(2))28    SIGWINCH     discard signal       Window size change29    SIGINFO      discard signal       status request from keyboard30    SIGUSR1      terminate process    User defined signal 131    SIGUSR2      terminate process    User defined signal 2

函数signal

void (*signal(int sig, void (*func)(int)))(int);or in the equivalent but easier to read typedef'd version:typedef void (*sig_t) (int);sig_t signal(int sig, sig_t func);

Unix使用信号的接口就是signal函数。在前面的章节中提到过signal函数的定义和具体意义。signal函数实际上是ISO C定义的,但是由于这种跨平台函数具有实现的不同,所以windows还是Unix各个实现,实际上都有其特殊的方式。对于函数本身来说,带有两个参数,一个是signo信号名,func的值是一个常亮

1     SIGHUP       terminate process    terminal line hangup2     SIGINT       terminate process    interrupt program3     SIGQUIT      create core image    quit program4     SIGILL       create core image    illegal instruction5     SIGTRAP      create core image    trace trap6     SIGABRT      create core image    abort program (formerly SIGIOT)7     SIGEMT       create core image    emulate instruction executed8     SIGFPE       create core image    floating-point exception9     SIGKILL      terminate process    kill program10    SIGBUS       create core image    bus error11    SIGSEGV      create core image    segmentation violation12    SIGSYS       create core image    non-existent system call invoked13    SIGPIPE      terminate process    write on a pipe with no reader14    SIGALRM      terminate process    real-time timer expired15    SIGTERM      terminate process    software termination signal16    SIGURG       discard signal       urgent condition present on socket17    SIGSTOP      stop process         stop (cannot be caught or ignored)18    SIGTSTP      stop process         stop signal generated from keyboard19    SIGCONT      discard signal       continue after stop20    SIGCHLD      discard signal       child status has changed21    SIGTTIN      stop process         background read attempted from control terminal22    SIGTTOU      stop process         background write attempted to control terminal23    SIGIO        discard signal       I/O is possible on a descriptor (see fcntl(2))24    SIGXCPU      terminate process    cpu time limit exceeded (see setrlimit(2))25    SIGXFSZ      terminate process    file size limit exceeded (see setrlimit(2))26    SIGVTALRM    terminate process    virtual time alarm (see setitimer(2))27    SIGPROF      terminate process    profiling timer alarm (see setitimer(2))28    SIGWINCH     discard signal       Window size change29    SIGINFO      discard signal       status request from keyboard30    SIGUSR1      terminate process    User defined signal 131    SIGUSR2      terminate process    User defined signal 2If a process explicitly specifies SIG_IGN as the action for the signal SIGCHLD, the system will not create zombie processes when children of the callingprocess exit.  As a consequence, the system  will discard the exit status from the child processes.  If the calling process subsequently issues a call to wait(2) or equivalent, it will block until all of the calling process's children terminate, and then return a value of -1 with errno set to ECHILD.

上面这些是苹果系统列出的可使用的信号,如果func参数可以指定3种,分别是常量SIG_IGN、常量SIG_DFL或者一个函数指针。常量SIG_IGN表示内核忽略此信号,常量SIG_DFL表示执行内核默认动作,函数指针则是当信号发生时,调用该函数,一般叫做信号处理函数。

结合前文中对signal函数的理解,实际上signal函数要求两个参数,只有一个返回值,signal函数第一个参数是signo信号名,第二个参数是一个函数指针,一般是信号处理函数,最后返回这个信号处理函数指针。由于函数原型非常复杂,一般都是使用typedef将其简化。

#define SIG_DFL         (void (*)(int))0#define SIG_IGN         (void (*)(int))1#define SIG_HOLD        (void (*)(int))5#define SIG_ERR         ((void (*)(int))-1)

一般声明就是像上面一样。下面是一个例程

#include "include/apue.h"static void sig_usr(int);int main(int argc, char *argv[]){    if (signal(SIGUSR1, sig_usr) == SIG_ERR)        err_sys("can't catch SIGUSR1");    if (signal(SIGUSR2, sig_usr) == SIG_ERR)        err_sys("can't catch SIGUSR2");    for ( ; ; )        pause();}static void sig_usr(int signo){    if (signo == SIGUSR1)        printf("received SIGUSR1\n");    else if (signo == SIGUSR2)        printf("received SIGUSR2\n");    else        err_dump("received signal %d\n", signo);}

然后编译运行

> ./a.out &[1] 21588> kill -USR1 21588received SIGUSR1> kill -USR2 21588received SIGUSR2> kill 21588[1]  + 21588 terminated  ./a.out

我们知道,所有的进程都是内核启动的,当启动一个进程的时候,所有的信号都会被设置为系统默认或者忽略,在Unix环境中最典型的一个例子就是shell启动其他进程,为了保证前台和后台对中断信号和退出信号的捕捉,一般都这样写

void sig_int(int), sig_quit(int);if (signal(SIGINT, SIG_IGN) != SIG_IGN)    signal(SIGINT, sig_int);if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)    signal(SIGQUIT, sig_quit);

因为所有都是被子进程继承的,所以在exec时,父进程可以控制子进程的忽略状态,所以需要这样判断。

在上面可以看出,signal函数除了改变当前信号的处理方式以外,还会返回之前的状态,这就非常的繁琐,所以在实际中很少使用了。

可重入函数

信号是异步调用,进程自身执行各种正常指令序列,当接受到信号的时候,内核就会通知进程处理,而此时正常的指令序列就会被中断,很容易造成进程空间的破坏,所以现在的Unix实现都会提供在信号处理程序中保证安全调用的函数,通俗的说,就是异步信号安全。至于具体列表,则需要查看具体Unix实现。

在前面学习errno错误信息的时候讲到过,每个进程都维护了一个errno变量,当需要获得的时候就通过extern int errno的形式获取。当然实际不是这样的,因为有多线程的模型存在,所以实际情况更加复杂。当进程执行正常代码,然后调用的系统函数修改了errno值,如果一个信号被发送给进程,进程的信号处理函数调用了另一个系统函数修改errno值,结果最终返回的时候就是信号处理程序内调用得到的errno,所以在实际开发中,如果需要调用系统函数,需要先保存errno值,然后调用后恢复errno

转载地址:http://pkncx.baihongyu.com/

你可能感兴趣的文章
netty-当一个客户端连接到来的时候发生了什么
查看>>
PHP_5.3.20 源码编译安装PHP-FPM
查看>>
在51CTO三年年+了,你也来晒晒
查看>>
js控制图片等比例缩放
查看>>
Java高级开发工程师面试考纲
查看>>
FreeMarker表达式
查看>>
Debian9.2 下使用vnstat查看服务器带宽流量统计
查看>>
NGINX + PHP-FPM 502
查看>>
mysql数据备份与恢复
查看>>
Openstack API常用命令
查看>>
OpenSSL漏洞凶猛来袭 慧眼恶意代码监测应对有方
查看>>
C语言 喝汽水问题
查看>>
LINUX中搭建DNS服务器,实现正向、反向以及访问不同DNS解析
查看>>
SCCM2012 R2实战系列之十:解决WDS服务无法启动问题(错误1067:进程意外终止)...
查看>>
怎么防止重复发送Ajax
查看>>
ubuntu 下安装 mysql
查看>>
关于k-means聚类算法的matlab实现
查看>>
Git分支2
查看>>
一键安装Gitlab后的备份、迁移与恢复
查看>>
因为本人工作繁忙,精力有限,本博客停止更新。有兴趣的博友可以关注我在CSDN上的主博客...
查看>>