Linux被中断的系统调用
<p>慢系统调用,指的是可能永远无法返回,从而使进程永远壅闭的系统调用,好比无客户毗连时的accept、无输入时的read都属于慢速系统调用。<br />在Linux中,当壅闭于某个慢系统调用的进程捕获一个信号,则该系统调用就会被停止,转而实行信号处置惩罚函数,这就是被停止的系统调用。<br />
然而,当信号处置惩罚函数返回时,有可能发生以下的情况:</p>
<ul>
<li>如果信号处置惩罚函数是用signal注册的,系统调用会自动重启,函数不会返回</li>
<li>如果信号处置惩罚函数是用sigaction注册的
<ul>
<li>默认情况下,系统调用不会自动重启,函数将返回失败,同时errno被置为EINTR</li>
<li>只有停止信号的SA_RESTART标记有效时,系统调用才会自动重启</li>
</ul></li>
</ul>
<p>下面我们编写代码,分别验证上述几种情况,此中系统调用选择read,停止信号选择SIGALRM,停止信号由alarm产生。</p>
<p><strong>利用signal</strong></p>
<code>#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;
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;
}</code>
<p><div align="center"></div></p>
<p><strong>利用sigaction + 默认情况</strong></p>
<code>#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;
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;
}</code>
<p><div align="center"></div></p>
<p><strong>利用sigaction + 指定SA_RESTART标记</strong></p>
<code>#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;
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;
}</code>
<p><div align="center"></div></p>
<p>由于对被停止系统调用处置惩罚方式的差异性,因此对应用步伐来说,与被停止的系统调用相干的题目是:</p>
<ul>
<li>应用步伐无法包管总是知道信号处置惩罚函数的注册方式,以及是否设置了SA_RESTART标记</li>
<li>可移植的代码必须显式处置惩罚关键函数的堕落返回,当函数堕落且errno等于EINTR时,可以根据实际需求举行相应处置惩罚,好比重启该函数</li>
</ul>
<code>int nread = read(fd, buf, 1024);
if (nread < 0)
{
if (errno == EINTR)
{
//read被停止,实在不应该算作失败,可以根据实际需求举行处置惩罚,好比重写调用read,也可以忽略它
}
else
{
//read真正的读错误
}
}</code><br><br/><br/><br/><br/><br/>来源:<a href="https://www.cnblogs.com/songhe364826110/p/11657198.html" target="_blank">https://www.cnblogs.com/songhe364826110/p/11657198.html</a>
页:
[1]