Linux被中断的系统如何调用详解

 更新时间:2019年10月12日 08:23:11   作者:原野追逐  
这篇文章主要给大家介绍了关于Linux被中断的系统如何调用的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Linux具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

前言

慢系统调用,指的是可能永远无法返回,从而使进程永远阻塞的系统调用,比如无客户连接时的accept、无输入时的read都属于慢速系统调用。

在Linux中,当阻塞于某个慢系统调用的进程捕获一个信号,则该系统调用就会被中断,转而执行信号处理函数,这就是被中断的系统调用。

然而,当信号处理函数返回时,有可能发生以下的情况:

  • 如果信号处理函数是用signal注册的,系统调用会自动重启,函数不会返回
  • 如果信号处理函数是用sigaction注册的
    • 默认情况下,系统调用不会自动重启,函数将返回失败,同时errno被置为EINTR
    • 只有中断信号的SA_RESTART标志有效时,系统调用才会自动重启

下面我们编写代码,分别验证上述几种情形,其中系统调用选择read,中断信号选择SIGALRM,中断信号由alarm产生。

使用signal

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>

void handler(int s)
{
  printf("read is interrupt by signal handler\n");
  return;
}

int main()
{
  char buf[10];
  int nread = 0;

  signal(SIGALRM, handler);
  alarm(2);

  printf("read start\n");
  nread = read(STDIN_FILENO, buf, sizeof(buf));
  printf("read return\n");

  if ((nread < 0) && (errno == EINTR))
  {
    printf("read return failed, errno is EINTR\n");
  }

  return 0;
}

使用sigaction + 默认情况

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>

void handler(int s)
{
  printf("read is interrupt by signal handler\n");
  return;
}

int main()
{
  char buf[10];
  int nread = 0;
  struct sigaction act;

  sigemptyset(&act.sa_mask);
  act.sa_handler = handler;
  act.sa_flags = 0; //不给SIGALRM信号设置SA_RESTART标志,使用sigaction的默认处理方式
  //act.sa_flag |= SA_INTERRUPT; //SA_INTERRUPT是sigaction的默认处理方式,即不自动重启被中断的系统调用
  //实际上,不管act.sa_flags值为多少,只要不设置SA_RESTART,sigaction都是按SA_INTERRUPT处理的

  sigaction(SIGALRM, &act, NULL);
  alarm(2);

  printf("read start\n");
  nread = read(STDIN_FILENO, buf, sizeof(buf));
  printf("read return\n");

  if ((nread < 0) && (errno == EINTR))
  {
    printf("read return failed, errno is EINTR\n");
  }

  return 0;
}


使用sigaction + 指定SA_RESTART标志

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>

void handler(int s)
{
  printf("read is interrupt by signal handler\n");
  return;
}

int main()
{
  char buf[10];
  int nread = 0;
  struct sigaction act;

  sigemptyset(&act.sa_mask);
  act.sa_handler = handler;
  act.sa_flags = 0;
  act.sa_flags |= SA_RESTART; //给SIGALRM信号设置SA_RESTART标志

  sigaction(SIGALRM, &act, NULL);
  alarm(2);

  printf("read start\n");
  nread = read(STDIN_FILENO, buf, sizeof(buf));
  printf("read return\n");

  if ((nread < 0) && (errno == EINTR))
  {
    printf("read return failed, errno is EINTR\n");
  }

  return 0;
}


由于对被中断系统调用处理方式的差异性,因此对应用程序来说,与被中断的系统调用相关的问题是:

  • 应用程序无法保证总是知道信号处理函数的注册方式,以及是否设置了SA_RESTART标志
  • 可移植的代码必须显式处理关键函数的出错返回,当函数出错且errno等于EINTR时,可以根据实际需求进行相应处理,比如重启该函数
int nread = read(fd, buf, 1024);

if (nread < 0)
{
  if (errno == EINTR)
  {
    //read被中断,其实不应该算作失败,可以根据实际需求进行处理,比如重写调用read,也可以忽略它
  }
  else
  {
    //read真正的读错误
  }
}

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。

相关文章

  • 一次Linux修改MySQL配置不生效的问题解决

    一次Linux修改MySQL配置不生效的问题解决

    这篇文章主要给大家介绍了关于Linux修改MySQL配置不生效问题的解决方法,文中通过示例代码介绍的非常详细,对大家学习或者使用Linux系统具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-08-08
  • LNMP下FTP服务器的安装与使用方法(Pureftpd和Proftpd)

    LNMP下FTP服务器的安装与使用方法(Pureftpd和Proftpd)

    FTP是网站文件维护中使用比较多的,目前LNMP一键安装包中有Pureftpd和Proftpd服务器安装脚本
    2013-06-06
  • 系统讲解Apache Kafka消息管理与异常处理的最佳实践

    系统讲解Apache Kafka消息管理与异常处理的最佳实践

    Apache Kafka 作为分布式流处理平台的核心组件,广泛应用于实时数据管道、日志聚合和事件驱动架构,下面我们就来系统讲解 Kafka 消息管理与异常处理的最佳实践吧
    2025-04-04
  • Linux 服务器安全配置

    Linux 服务器安全配置

    Linux 服务器安全配置,需要的朋友可以参考下
    2012-03-03
  • Linux系统中卸载与安装JDK的详细教程

    Linux系统中卸载与安装JDK的详细教程

    本文详细介绍了如何在Linux系统中通过Xshell和Xftp工具连接与传输文件,然后进行JDK的安装与卸载,安装步骤包括连接Linux、传输JDK安装包、解压并配置环境变量,卸载过程则涉及查找JDK路径、删除文件及更新环境变量,需要的朋友可以参考下
    2025-04-04
  • apache提示Failed loading ZendLoader.dll解决方法

    apache提示Failed loading ZendLoader.dll解决方法

    这篇文章主要介绍了apache提示Failed loading ZendLoader.dll解决方法,需要的朋友可以参考下
    2015-04-04
  • CentOS 6 启动流程详细介绍

    CentOS 6 启动流程详细介绍

    这篇文章主要介绍了CentOS 6 启动流程详细介绍的相关资料,这里对centos 启动进行了分析,希望能帮助到大家理解centos 启动流程,需要的朋友可以参考下
    2017-07-07
  • Linux 字符设备驱动框架详细介绍

    Linux 字符设备驱动框架详细介绍

    这篇文章主要介绍了Linux 字符设备驱动框架详细介绍的相关资料,字符设备就是字节流形式通讯的I/O设备,绝大部分设备都是字符设备,这里提供简单的实例,需要的朋友可以参考下
    2016-12-12
  • Linux修改主机名(hostname)的两种方法(亲测可用)

    Linux修改主机名(hostname)的两种方法(亲测可用)

    要想在虚拟机的 Linux 系统内部改变主机名(hostname),需要通过系统的配置来修改,在大多数基于 Red Hat 的 Linux 发行版(比如 CentOS、Fedora)中,本文小编给大家介绍了;两种修改主机名的方法,感兴趣的小伙伴跟着小编一起来看看吧
    2023-11-11
  • Apache配置域名跳转的详细步骤

    Apache配置域名跳转的详细步骤

    域名跳转就是实现URL的跳转和隐藏真实地址,基于Perl语言的正则表达式规范,平时帮助我们实现拟静态,拟目录,域名跳转,防止盗链等,本文小编给大家介绍了Apache配置域名跳转的详细步骤,需要的朋友可以参考下
    2025-04-04

最新评论