zoukankan      html  css  js  c++  java
  • 被信号中断的系统调用

    被信号中断的系统调用

    1:EINTR

      一般来说, 一个阻塞的慢系统调用(ex: read, write)被信号中断后, 有以下几种情况.

      1.1 按照信号默认的处理方式, 如本进程直接退出

      1.2 如果有信号处理函数, 系统调用返回-1(一般的错误返回), 且errno的值被系统置为EINTR(数值为4), 这时并不表示系统调用失败, 应该要重启系统调用

    2:重启系统调用

      所谓重启系统调用, 就是某个系统调用执行期间被某个信号中断, 但系统调用不立即返回错误, 而是重启, 重启系统调用就是设置某个信号的SA_RESTART标志, 被此信号中断的系统调用将重启而不是返回错误, 但SA_RESTART标志并不是对所有的系统调用都有效。

      2.1 设置SA_RESTART

    #include <stdio.h>
    #include <signal.h>
    #include <errno.h>
    #include <string.h>
    #include <unistd.h>
    
    void int_handler(int signo){
    
        printf("Got SIGINT signal
    ");
    }
    
    int main(int argc, char const *argv[])
    {
        char buf[1024] = {0};
        int n;
        struct sigaction act, oldact;
        act.sa_handler = int_handler;
        sigemptyset(&act.sa_mask);
        act.sa_flags |= SA_RESTART;
        sigaction(SIGINT, &act, &oldact);
        while(1){
            memset(buf, 0, sizeof buf);
            if((n = read(STDIN_FILENO, buf, sizeof buf)) < 0){
                if(errno == EINTR){// 等待终端输入时被SIGINT中断
                    perror("read interrupt by sigint");
                    continue;
                }
            }
    
            if(buf[0] == 'q' || buf[0] == 'Q')
                break;
            printf("Got:%s
    ", buf);
        }
        sigaction(SIGINT, &oldact, NULL);
        return 0;
    }

    结果及分析:

    stone@cdWSCMPL07:~/test_my$ ./read 
    ^CGot SIGINT signal
    ^CGot SIGINT signal
    ^CGot SIGINT signal
    ^CGot SIGINT signal
    ^CGot SIGINT signal
    ^CGot SIGINT signal
    ^CGot SIGINT signal
    ^CGot SIGINT signal
    q
    stone@cdWSCMPL07:~/test_my$

      如上, read函数在阻塞过程中被SIGINT中断, 因为信号SIGINT设置了SA_RESTART标志的原因, 所以程序仅仅执行了信号处理函数, read函数并没有返回, 而被重启并进入下一次阻塞。

      2.2 取消设置SA_RESTART

      将语句 act.sa_flags |= SA_RESTART; 屏蔽

    结果及分析:

    stone@cdWSCMPL07:~/test_my$ ./read 
    ^CGot SIGINT signal
    read interrupt by sigint: Interrupted system call
    ^CGot SIGINT signal
    read interrupt by sigint: Interrupted system call
    ^CGot SIGINT signal
    read interrupt by sigint: Interrupted system call
    ^CGot SIGINT signal
    read interrupt by sigint: Interrupted system call
    q
    stone@cdWSCMPL07:~/test_my$ 

      如上, 没有设置SA_RESTART的read被中断, read返回之后系统设置了errno, 并执行了perror打印, 最后continue后重新调用read进入下一次阻塞。

    3:SA_RESTART标志的适用范围

      并不是所有的系统调用都是支援SA_RESTART重启机制的, 所以要注意区分使用范围

      支援此标志的系统调用有:

        读写IO:read, readv, write, writev, ioctl

      不支持的如select

    4:总结

      对于SA_RESTART还是应该避免使用, 因为首先你要区别哪些系统调用支援哪些不支援, 这是一个比较麻烦的事情, 而且你需要对每个信号都设置此标志, 总的来讲, SA_RESTART标志是一个不建议使用的标志, 最合理的是将系统调用返回-1且errno=EINTR不纳入调用出错来考虑, 这种情况应该重新执行之前的代码来替代SA_RESTART重启系统调用。

  • 相关阅读:
    Tomcat 性能优化
    Centos下Tomcat 安装Apache Portable Runtime
    单机多实例Tomcat部署
    Maven 常用命令, 备忘
    IntelliJ IDEA运行tomcat项目编码错误, 及如何指定tomcat编码
    多个mapper location时, mybatis spring的自动扫描配置
    X200s,Debian 8(Jessie) 安装流水帐
    dubbo2.5.3 与spring 3.1.x 冲突
    IntelliJ Idea14 创建Maven多模块项目
    为EXSi5.5上的Centos虚机增加硬盘容量
  • 原文地址:https://www.cnblogs.com/Flychown/p/7716408.html
Copyright © 2011-2022 走看看