zoukankan      html  css  js  c++  java
  • 第十章 信号

    第十章 信号

    信号是由用户,系统或者进程发送给目标程序的信息,以通知目标程序某个状态的改变或系统异常。


    10.1 信号概述

    一.发送信号

    在Linux下,一个进程给其他进程发送信号的API是kill:

    int kill(pid_t pid,int sig);
    
    • pid:制定目标进程

    • sig:要发送的信号

    该函数成功时返回0,失败返回-1并设置error。

    二.信号处理方法

    目标进程在接受到信号后,需要定义一个处理的对应信号的函数,信号处理函数原型如下:

    #include <signal.h>
    typedef void (*sighandler_t)(int);
    
    • 可以看出信号处理函数只带有一个整型参数,该参数用来指示信号类型。

    • 信号处理函数应该是可重入的。

    除了用户自定义的信号处理函数外,还有两种其他的处理方式。

    #define SIG_DEL((sighandler_t) 0) 
    #define SIG_IGN((sighandler_t) 1)
    

    前者忽略目标警告,后者是使用默认处理方式。

    三.Linux信号

    会主要讲解与网络编程关系紧密的几个信号:

    • SIGHUP

    • SIGPIPE

    • SIGURG

    四.中断系统调用

    如果程序在执行处于阻塞状态的系统调用时接收到了信号,并且为该信号设置了信号处理函数,则默认情况下系统调用将被中断。


    10.2 信号函数

    为一个信号设置处理函数:

    sighandler_t signal(int signum, sighandler_t handler);
    
    • sig: 要捕获的信号类型

    • 指定信号sig的处理函数

    成功返回一个函数指针,错误返回SIG_ERR并设置error。

    但更为健壮的接口是如下的系统调用:

    int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
    
    • sig:指定要捕获的信号类型
    • act:指定新的信号处理方式,指定了对特定信号的处理
    • oact:指向的对象用来保存原来对应信号的处理

    sigaction结构体描述了信号处理的细节。

    struct sigaction {
                   void     (*sa_handler)(int);
                   void     (*sa_sigaction)(int, siginfo_t *, void *);
                   sigset_t   sa_mask;
                   int        sa_flags;
                   void     (*sa_restorer)(void);
               };
    
    • sa_mask:设置进程的信号掩码。

    • sa_flags:用于设置程序收到信号时的行为。


    10.3 信号集

    一.信号集函数

    Linux使用数据结构sigset_t来表示一组信号,sigset_t是一个长整型数组,数组的每个元素的每个位表示一个信号(和fd_set类似),故也提供了一组函数来设置,修改,删除和查询信号集。

    int sigemptyset(sigset_t *set);
    int sigfillset(sigset_t *set);
    int sigaddset(sigset_t *set, int signum)
    int sigdelset(sigset_t *set, int signum);
    int sigismember(const sigset_t *set, int signum);
    

    二.进程信号掩码

    可以利用sigaction结构体的sa_mask设置进程的信号掩码,也可以用如下函数设置或者查看进程的信号掩码:

    int sigprocmask(int _how, const sigset_t * _set, sigset_t * _oset);
    
    • _how:指定设置进程信号掩码的方式。

    • _set:指定新的信号掩码。

    • _oset:输出的信号掩码,若_set为NULL,则进程信号掩码不变,此时可以利用_oset参数来获得当前的信号掩码。

    三.被挂起的信号

    设置进程信号掩码后,被屏蔽的信号将不能被进程接受。如果给进程发送一个被屏蔽的信号,则操作系统将该信号设置为进程的一个被挂起信号。若取消对被挂起信号的屏蔽,则它能立即被进程接收到。

    如下函数用来获取被挂起的信号集:

    int sigpending(sigset_t *set);
    
    • set:用于保存挂起的信号集

    关于信号和信号集,Linux还提供了许多很有用的API,面面俱到肯定没有必要。

    要始终清楚的知道进程在每个运行时刻的信号掩码,以及如何适当的处理捕捉到的信号,在多进程,多线程的环境中要以进程,线程为单位类处理信号和信号掩码。


    10.4 统一事件源

    信号是一种异步事件,信号处理函数主循环是两条不同的执行路线,所以,信号处理函数需要尽可能的快速执行完毕,以确保信号不被屏蔽,一种典型的解决方案是:把信号的主要处理逻辑放到主循环中,而主循环根据接收到的信号值执行对应的逻辑代码,实现方式一般为信号处理函数往管道的写端写入数据,主循环则从管道的读端读出该数据。

    那么问题来了,主循环怎么知道管道上何时有数据可读呢?

    答:只需要使用I/O复用系统调用来监听管道的读端的文件描述符上的可读事件。

    如此一来,信号事件就能和其他I/O事件一样被处理,即统一事件源。


    10.5 三个与网络编程相关的信号

    SIGHUP SIGURG SIGPIPE
    当挂起进程的控制终端时将会引发此信号 内核通知应用程序带外数据到达将引发此信号 (默认情况下)往一个读端关闭的管道或socket连接中写数据将引发此信号

    关于第十章的总结

    • 了解了如何在程序中发送信号和处理信号。

    • 服务端程序必须处理一些常见的信号,以避免异常终止。

    本章涉及到的代码有:


    From

    Linux 高性能服务器编程

    MarkdownPad2

    Aaron-z/linux-server-high-performance

    2017/2/9 18:42:54

  • 相关阅读:
    客户端IP获取
    文件下载公共方法 以及调用
    文件压缩和解压缩工具类
    下载
    URLencoder类防止下载后的文件名乱码
    SQL行转列
    处理千万级以上的数据提高查询速度的方法
    获取本月的第一天和最后一天
    【机器学习理论】概率论与数理统计--假设检验,卡方检验,t检验,F检验,方差分析
    【机器学习实践】Jupyter Notebook安装 侧边导航栏功能 操作及其他常用扩展功能介绍
  • 原文地址:https://www.cnblogs.com/leihui/p/6394450.html
Copyright © 2011-2022 走看看