Linux被中断的系统调用
2019-10-12 08:09:27来源:博客园 阅读 ()
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真正的读错误
}
}
原文链接:https://www.cnblogs.com/songhe364826110/p/11657198.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- Linux系统如何设置开机自动运行脚本? 2020-06-11
- Linux指令和shell脚本 2020-06-11
- 适合开发者的最佳Linux发行版 2020-06-11
- RAID 1 软件实现(Linux 系统) 2020-06-10
- linux各级目录 2020-06-08
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash