很多系统调用如close( fd )
可以被信号中断。 在这种情况下通常返回-1
, errno
被设置为EINTR
。
问题是什么是正确的做法? 说,我仍然希望这个fd
被closures。
我能想到的是:
while( close( fd ) == -1 ) if( errno != EINTR ) { ReportError(); break; }
有人可以build议一个更好/更优雅/标准的方式来处理这种情况?
更新:正如注意到的多路复用器,安装信号处理程序时可以使用SA_ RESTART
标志。 有人可以告诉我哪些function可以在所有POSIX
系统(不仅仅是Linux
)上重新启动吗?
有些系统调用是可重新启动的,这意味着如果中断,内核将重新启动调用,如果在安装信号处理程序时使用了SA_RESTART
标志,那么信号(7)手册页将显示:
如果以下接口之一的阻塞呼叫被信号处理程序中断, 则在信号处理程序返回后,如果使用SA_RESTART标志,呼叫将自动重新启动 ; 否则该调用将失败,出现错误EINTR:
它没有提到close()
是否可重启,但是它们是:
(2),readv(2),write(2),writev(2),ioctl(2),open(2),wait(2),wait3(2),wait4(2),waitid(2), (2),connect(2),recv(2),recvfrom(2),recvmsg(2),send(2),sendto(2),sendmsg(2)flock(2)和fcntl 2)mq_receive(3),mq_timedreceive(3),mq_send(3)和mq_timedsend(3)sem_wait(3)和sem_timedwait(3)futex(2)
请注意,这些详细信息,特别是不可重新启动的调用列表,都是Linux特有的
我发布了一个关于哪些系统调用是可重启的相关问题,如果是由POSIX指定的,它是由POSIX指定的,但是它是可选的,所以你应该检查你的操作系统的不可重启调用列表,如果它不是应该重新启动。 这是我的问题: 如何知道Linux系统调用是否可重启?
更新:关闭是一种特殊情况,它不能重新启动,不应该在Linux中重试,请参阅此答案的更多详细信息: https : //stackoverflow.com/a/14431867/1157444
记录:在基本上每个UNIX上,如果返回EINTR,则close()
不得重试 。 不要像waitpid()
或read()
那样放置一个EINTR重试循环。 有关更多详细信息,请参阅此页面: http : //austingroupbugs.net/view.php?id=529在linux,Solaris,BSD等上,重试close()
不正确。 HP-UX是唯一可以找到的常见(!)系统。
对于read()
和select()
和waitpid()
等,EINTR的含义与close()
。 对于大多数电话,您在EINTR上重试,因为您要求完成哪些功能,如果您被打断,意味着它没有发生,所以您再试一次。 对于close()
,你要求的动作是从fd表中删除一个条目,这是瞬时的,没有错误,并且无论close()
返回什么都会发生。[*] close()
块的唯一原因有时候,对于特殊的语义(比如TCP连接),它可以等到I / O完成才返回。 如果关闭返回EINTR,这意味着你要求它等待,但它不能。 但是, FD仍然是封闭的 ; 你只是失去了等待的机会。
结论:除非你知道你不能接收信号,否则使用close()
等待是一件非常愚蠢的事情。 使用应用程序级别的ACK(TCP)或fsync(文件I / O)来确保在关闭fd之前完成了任何写入操作。
有一个警告:如果进程的另一个线程在同一个fd上的阻塞系统调用内部,那么…取决于。
假设你在更短的代码之后,你可以尝试如下所示:
while (((rc = close (fd)) == -1) && (errno == EINTR)); if (rc == -1) complainBitterly (errno);
假设除了较短的代码之外,您还可以使用更易读的代码,只需创建一个函数:
int closeWithRetry (int fd);
并把你的可读代码放在那里。 那么它的长度并不重要,它仍然是你调用它的一行,但是你可以使函数体本身非常易读:
int closeWithRetry (int fd) { // Initial close attempt. int rc = close (fd); // As long as you failed with EINTR, keep trying. // Possibly with a limit (count or time-based). while ((rc == -1) && (errno == EINTR)) rc = close (fd); // Once either success or non-retry failure, return error code. return rc; }