Windows中的命名管道,FILE_FLAG_OVERLAPPED和PIPE_NOWAIT之间的区别
Posted
技术标签:
【中文标题】Windows中的命名管道,FILE_FLAG_OVERLAPPED和PIPE_NOWAIT之间的区别【英文标题】:Named pipe in windows, difference between FILE_FLAG_OVERLAPPED and PIPE_NOWAIT 【发布时间】:2018-11-10 09:46:52 【问题描述】:我在windows中使用命名管道,对FILE_FLAG_OVERLAPPED
和PIPE_NOWAIT
之间的区别感到困惑,这是CreateNamedPipe
中设置的参数,我这样设置参数。
HANDLE hPipe = CreateNamedPipe(
lpszPipename, // pipe name
PIPE_ACCESS_DUPLEX | // read/write access
FILE_FLAG_OVERLAPPED, // overlapped mode
PIPE_TYPE_MESSAGE | // message-type pipe
PIPE_READMODE_MESSAGE | // message read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // unlimited instances
BUFSIZE * sizeof(TCHAR), // output buffer size
BUFSIZE * sizeof(TCHAR), // input buffer size
PIPE_TIMEOUT, // client time-out
NULL); // default security attributes
ConnectNamedPipe
立即返回,我从GetLastError
得到ERROR_IO_PENDING
。使用非阻塞等待句柄,连接操作立即返回零,GetLastError 函数返回ERROR_IO_PENDING
。但是 MSDN 告诉:
使用非阻塞等待句柄,连接操作立即返回零,GetLastError 函数返回ERROR_PIPE_LISTENING。
那么,nonblocking-wait
是什么意思,PIPE_NOWAIT
或 FILE_FLAG_OVERLAPPED
,非常感谢!
【问题讨论】:
似乎MSDN在使用PIPE_ NOWAIT
时使用术语“非阻塞模式”,在使用@987654334时使用术语“重叠模式” @。 PIPE_NOWAIT
是 "supported for compatibility with Microsoft LAN Manager version 2.0 and should not be used to achieve asynchronous I/O"。
非常不同的选项。 FILE_FLAG_OVERLAPPED 设置套接字以便它可以处理异步 I/O,您可以使用 OVERLAPPED 参数调用 ReadFile() 并稍后处理读取完成。管道很常见,除非流量非常高,否则您想避免过多地阻塞线程。 PIPE_NOWAIT 对于同步 I/O 很有用,它可以防止 ReadFile() 在没有数据的情况下阻塞。然后需要反复调用 ReadFile(),以通用术语进行轮询。看看像 boost::asio 这样的库来处理管道。
【参考方案1】:
PIPE_NOWAIT
表示在句柄上启用了非阻塞模式。在这种模式下,ReadFile
、WriteFile
和 ConnectNamedPipe
总是立即完成。
FILE_FLAG_OVERLAPPED
表示在句柄上启用了异步模式。如果启用此模式,所有非同步 io [1] 操作总是立即返回。
所以FILE_FLAG_OVERLAPPED
vs PIPE_NOWAIT
- 这是立即返回 vs 完成立即。
completed立即(包括return立即)表示api返回时io操作已经完成。但反之亦然。如果操作立即返回,这并不意味着操作已经完成。如果操作仍未完成 ntapi 返回码STATUS_PENDING
。 win32 api 在这种情况下通常将最后一个错误设置为ERROR_IO_PENDING
。
在异步句柄模式下,存在 3 种方式确定 io 操作何时完成。
-
将句柄绑定到IOCP(通过
CreateIoCompletionPort
或
BindIoCompletionCallback
或 CreateThreadpoolIo
)。结果当
io 完成 - 指向 OVERLAPPED
的指针,我们将其传递给 io 调用 -
将排队返回 IOCP(如果是 BindIoCompletionCallback
或
CreateThreadpoolIo
系统自己创建 IOCP 并监听它
并调用我们注册的回调,当指向OVERLAPPED
的指针将
排队到IOCP)
一些win32 api如ReadFileEx
或WriteFileEx
和所有ntapi让
指定将在上下文中调用的 APC 完成例程
io 操作完成时开始 io 操作的线程。
在这种情况下,线程必须执行警报等待。这个等待不是
与 IOCP 的绑定句柄兼容(我们不能在
如果文件句柄绑定到 IOCP,则 api 调用 - 系统返回无效
参数错误)
我们可以创建事件并将其传递给 api 调用(通过
OVERLAPPED::hEvent
) - 在这种情况下,此事件将被重置
io 操作开始时的系统,并在 io 时设置为信号状态
操作完成。在这种情况下,与前 2 个选项不同,我们有
io 时没有额外的上下文(在指向OVERLAPPED
的指针中)
操作完成。通常这是最糟糕的选择。
[1] 存在一些始终是同步 api 的 io 操作。例如GetFileInformationByHandleEx
、SetFileInformationByHandle
。但几乎 io 操作不是同步 io。所有这些 io 操作都将指向 OVERLAPPED
的指针作为参数。因此,如果 api 签名中没有指向 OVERLAPPED
的指针 - 这是同步 api 调用。如果存在 - 通常是异步的(例如 CancelIoEx
异常,其中指向重叠的指针与当前操作无关,而是与我们想要取消的先前 io 操作相关)。特别是ReadFile
,WriteFile
,DeviceIoControl
,ConnectNamedPipe
(内部这是调用DeviceIoControl
和FSCTL_PIPE_LISTEN
))不是同步io api
【讨论】:
以上是关于Windows中的命名管道,FILE_FLAG_OVERLAPPED和PIPE_NOWAIT之间的区别的主要内容,如果未能解决你的问题,请参考以下文章
适用于 Windows 和 Linux 的 Go 中的命名管道
Windows 中的 python 2 和 python 3 之间的命名管道的工作方式有啥不同吗?
从底层的角度来看,Windows 中的命名管道和远程过程调用 (RPC) 有啥区别?