慢系统调用,指的是可能永远无法返回,从而使进程永远阻塞的系统调用,比如无客户连接时的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真正的读错误
}
}

最新文章

  1. 学习Word2vec
  2. LeftoverDataException.
  3. JIRA 6.3.6版本部署
  4. CGContextRef使用简要教程
  5. AngularJs学习笔记--bootstrap
  6. 【多线程】Java并发编程:并发容器之CopyOnWriteArrayList(转载)
  7. careercup-数组和字符串1.7
  8. hdu 4602 Partition(矩阵快速幂乘法)
  9. MAC安装Securecrt破解
  10. Java进阶篇(一)——接口、继承与多态
  11. c# 抽象类,抽象方法使用(abstract)
  12. css中font-size为0的妙用(消除内联元素间的间隔)
  13. spring boot中利用mybatis-generator插件生成代码
  14. 本学期Windows编程微型技术博客上线!
  15. js中 &amp;&amp; 和 || 的用法
  16. CSS 小技巧(不定时更新)
  17. [MHA]master_ip_failover 测试可以使用的IP 地址切换脚本
  18. 如何seo(搜索引擎优化)
  19. Http User Agent Example
  20. POCO Log库

热门文章

  1. CF1072A Palindromic Twist 思维
  2. Fractions Again?! UVA - 10976
  3. odoo12从零开始:一、安装odoo运行环境(windows10)
  4. mysql 复制表结构和表数据
  5. 创建多线程之threading.Thread的使用
  6. myeclipse 保存含中文的jsp失败,提示内容含有 ISO-8859-1 不支持的字符
  7. 遇到XML-GB2312网页编码的处理方法
  8. 一个基于vue的仪表盘demo
  9. js中Math对象常用的属性和方法
  10. Python语法基础之对象(字符串、列表、字典、元组)