gpt4 book ai didi

nonblocking - EINTR和非阻塞调用

转载 作者:行者123 更新时间:2023-12-03 20:10:10 25 4
gpt4 key购买 nike

众所周知,某些阻塞调用,例如readwrite将返回-1并将errno设置为EINTR,我们需要对此进行处理。

我的问题是:这是否适用于非阻塞调用,例如,将套接字设置为O_NONBLOCK

由于我已经阅读了一些文章和资料,所以说无阻塞调用并不需要为此烦恼,但是我发现没有权威性的参考。如果是这样,它是否适用于不同的实现?

最佳答案

对于该问题,我无法给出确切的答案,并且答案可能会因系统而异,但是我希望非阻塞套接字永远不会因EINTR而失败。如果查看以下套接字功能bind()connect()send()receive()的各种系统的手册页,或者在POSIX标准中查找这些内容,您会发现一些有趣的事情:除一个功能外,所有这些功能都可能返回-1并将errno设置为EINTR。未记录为EINTR失败的一个功能是bind()。并且bind()也是该列表中唯一在默认情况下永远不会阻止的功能。因此,似乎只有阻塞函数可能会因EINTR而失败,包括read()write(),但是如果这些函数从未阻塞,则它们也不会因EINTR而失败;如果您使用O_NONBLOCK,这些函数永远不会阻止。

从逻辑的角度来看,这也没有任何意义。例如。考虑到您正在使用阻塞I / O,并且您调用read()并且此调用必须阻塞,但是在阻塞时,信号将发送到您的进程,因此读取请求被解除阻塞。系统应如何处理这种情况?声称read()成功了吗?那将是一个谎言,它没有成功,因为没有读取任何数据。声称它确实成功了,但是读取了零字节数据?这也不正确,因为“零读取结果”用于指示流的末尾(或文件末尾),因此您的进程将假定未读取任何数据,因为文件已到达(或另一端的套接字/管道已关闭),事实并非如此。尚未到达文件末尾(或流末尾),如果再次调用read(),它将能够返回更多数据。因此,这也是一个谎言。您期望该读取调用成功并读取数据,或者由于错误而失败。因此,在这种情况下,读取调用必须失败并返回-1,但是系统应设置什么errno值?所有其他错误值都表明文件描述符存在严重错误,但没有严重错误,表明这种错误也可能是谎言。这就是将errno设置为EINTR的原因,这意味着:“流没有任何问题。您的读取调用只是失败了,因为它被信号中断了。如果没有被中断,则它可能仍然成功,因此,如果您仍然需要这些数据,请重试。”

如果现在切换到非阻塞I / O,则不会出现上述情况。读取调用将永远不会阻塞,并且如果无法立即读取数据,它将失败,并显示错误EAGAIN(POSIX)或EWOULDBLOCK(非官方的,在Linux上都是相同的错误,只是它的替代名称),这意味着:“目前没有可用数据,因此您的读取调用将不得不阻塞并等待数据到达,但不允许阻塞,因此失败了。”因此,每种情况都可能出现错误。

当然,即使在非阻塞I / O的情况下,读调用也可能会被信号暂时中断,但是系统为什么要指出呢?每个函数调用,无论是系统函数还是用户编写的函数,都可能会被信号暂时中断,实际上每个信号都不例外。如果系统必须在发生这种情况时通知用户,则所有系统功能都可能由于EINTR而失败。但是,即使发生信号中断,功能也通常会一直执行到最后,这就是为什么这种中断无关紧要的原因。错误EINTR用于告诉调用者,由于信号中断,未执行他所请求的操作,但是在非阻塞I / O的情况下,没有理由该函数不应执行读取或读取操作。写入请求,除非不能立即执行,但是可以通过适当的错误来指示。

为了证实我的理论,我看了一下MacOS(10.8)的内核,该内核仍主要基于FreeBSD内核,似乎证实了人们的怀疑。如果当前无法进行读取调用,因为没有可用数据,则内核会检查文件描述符标志中的O_NONBLOCK标志。如果设置了此标志,则它立即失败,并显示EAGAIN。如果未设置,则通过调用名为msleep()的函数使当前线程进入睡眠状态。函数是documented here(正如我所说,OS X在其内核中使用了大量的FreeBSD代码)。此函数使当前线程进入睡眠状态,直到显式唤醒它(如果数据已准备就绪,可以读取)或达到超时(例如,您可以在套接字上设置接收超时)。但是,如果传递了信号,线程也会被唤醒,在这种情况下,msleep()本身将返回EINTR,而下一个更高的层将传递此错误。因此,是msleep()会产生EINTR错误,但是如果设置了O_NONBLOCK标志,则首先不会调用msleep(),因此无法返回此错误。

当然那是MacOS / FreeBSD,其他系统可能有所不同,但是由于大多数系统试图在这些API之间至少保持一定程度的一致性,因此,如果系统违反了这一假设,则非阻塞I / O调用永远不会失败由于EINTR,这可能不是故意的,甚至在您举报时也可能得到解决。

关于nonblocking - EINTR和非阻塞调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14134440/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com