- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
众所周知,某些阻塞调用,例如read
和write
将返回-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/
IBM(请参阅源代码)阐述了 Java 1.5 java.util.concurrent 类的优点,该类提供非阻塞队列。 请在下面解释 NonBlockingCounter 的弱点/缺点。 publi
众所周知,某些阻塞调用,例如read和write将返回-1并将errno设置为EINTR,我们需要对此进行处理。 我的问题是:这是否适用于非阻塞调用,例如,将套接字设置为O_NONBLOCK? 由于我
我有一个使用非阻塞套接字运行的简单 TCP 服务器。 引用自 recv 的联机帮助页; When a stream socket peer has performed an orderly shutd
我无法理解任何数据结构如何“非阻塞”。 假设您正在创建一个“非阻塞”哈希表。在某些时候,您的散列表变得太满,因此您必须重新散列到一个更大的表中。 这意味着您需要分配内存,这是一种全局资源。所以看起来您
我有一个回调想执行一次。为了争论起见,我们假设它看起来像这样: final X once = new X(1); Runnable r = new Runnable() { @Override
我使用MPI非阻塞通信(MPI_Irecv, MP_Isend)来监控slaves的空闲状态,代码如下。 排名 0: int dest = -1; while( dest <= 0){ int
我正在努力在 epoll 和 kqueue 标志之间画一条平行线,特别是 EPOLLONESHOT EPOLLET EPOLLEXCLUSIVE 和 EV_CLEAR/EV_DISPATCH/EV_O
我正在尝试使用 O_NONBLOCK 模式创建命名管道,并在单独的线程中使用“SELECT”方法监听读取事件。当我在主线程中休眠一段时间后试图关闭程序时出现问题。我希望当使用 close 方法关闭命名
我是 Node 新手,并尝试了解 Node 的非阻塞性质。 在下图中,我创建了请求的高级图表。 据我了解,单个用户针对单个应用程序的所有进程都在单个线程上运行。 我想了解的是事件循环的逻辑如何适合该图
基于此question我想请教以下问题。假设阻塞 I/O 并且我有一段如下代码: byte[] data = new byte[10]; someInputStream.read(data) 此代码片
在 Ubuntu 16.04 服务器(内核 4.4.0-22)上,根据/var/log/syslog,与 Ubuntu 14.04 相比,初始化“随机:非阻塞池”需要 2-5 分钟: May 28 1
我是一名优秀的程序员,十分优秀!