问题标签 [overlapped-io]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
0 回答
981 浏览

windows - 为什么 I/O 完成端口中有 CompletionKey?

MSDN 关于CreateIoCompletionPort函数中的 CompletionKey 的评论:

使用 CompletionKey 参数帮助您的应用程序跟踪哪些 I/O 操作已完成。CreateIoCompletionPort 不使用此值进行功能控制;相反,它在与 I/O 完成端口关联时附加到 FileHandle 参数中指定的文件句柄。这个完成键对于每个文件句柄应该是唯一的,并且在整个内部完成排队过程中伴随文件句柄。当完成数据包到达时,它在 GetQueuedCompletionStatus 函数调用中返回。PostQueuedCompletionStatus 函数还使用 CompletionKey 参数来对您自己的专用完成数据包进行排队。

上面的评论给我留下了一个问题。为什么要使用 CompletionKey ,因为我们可以将用户上下文与文件句柄以扩展的重叠结构关联起来,如下所示:

并在完成后通过 CONTAINING_RECORD 宏检索?

酷,我只相信 CompletionKey 是每个句柄上下文,而扩展重叠结构是每个 I/O 一个。但是这种设计背后的理念是什么?在什么情况下,就用户上下文而言,有必要使用 CompletionKey 而不是扩展的重叠结构?

0 投票
2 回答
8577 浏览

windows - 如何判断 ReadFileEx() 重叠 I/O 何时完成?

HasOverlappedIoCompleted()不适用于以ReadFileEx()and开头的异步 I/O WriteFileEx()。底部的代码片段演示了这一点。在此示例中,ReadFileEx()从没有输入的管道读取,因此读取不会完成。但HasOverlappedIoCompleted()返回 TRUE。如果我将调用更改为重叠ReadFile()HasOverlappedIoCompleted()则按预期返回 FALSE。

我的问题是:如何在不依赖回调本身的情况下确定带有回调的重叠 I/O 请求是否已完成?在我的应用程序中,APC 可能已排队,但不一定已经运行,因为应用程序可能尚未在警报状态下等待。

谢谢。

(注意 GetOverlappedResult() 没有帮助 - 它也返回 TRUE。)

更多背景知识:在我使用的示例中,ReadFileEx()因为它很容易演示问题。在我的应用程序中,我WriteFileEx()在管道实例上反复调用。如果前一个WriteFileEx()还没有完成,我必须丢弃消息而不是发送它(我在同一个管道实例上不能有多个挂起的写入),但是如果前一个WriteFileEx() 已经完成,那么我必须开始下一个,即使完成回调尚未运行

编辑:问题场景的描述

  1. 线程进入警报状态(有一个读取 APC 排队)。
  2. 读取 APC 开始:它将 WriteFileEx() 排队并设置一个“写入挂起”标志。然后它将 ReadFileEx() 排队。
  3. 主线程开始工作(不可警报)。
  4. 排队读取完成。
  5. 排队的写入完成(在读取之后)。
  6. 主线程进入警报状态。
  7. 读取的 APC 在队列中排在第一位,因此首先运行:它查看“写入挂起”标志,并且由于它仍处于设置状态,因此它会放弃写入。事实上,虽然 WriteFileEx()已经完成,但它还没有调用它的 APC,因为 ReadFileEx() 先完成了。

我不想测试我的自定义“写入挂起”标志,而是想从操作系统中找出 WriteFileEx() 是否实际完成,即使 APC 尚未运行。


0 投票
1 回答
1050 浏览

c++ - 使用 Overlapped IO 获取 Sender 的 IP 地址

我知道 WSARecvFrom 有一个参数,用于返回发件人的 IP 地址。但是,当我将它与重叠 io 一起使用时,我传递给它的变量不会被填充。

incomingAddressString 现在等于“204.204.204.204”

我错过了什么吗?

谢谢

0 投票
2 回答
543 浏览

windows - 如何将主机名异步解析为 IP 地址?

您如何将主机名异步解析为 IP 地址,最好使用重叠 I/O?GetAddrInfoEx 不支持 Windows 7 和更早版本中的重叠 I/O。

我正在使用本机 C++。

0 投票
1 回答
883 浏览

c++ - WIN32 Socket API: Canceling Send/Recv on socket using event-based completion notification

using socket with the overlapped operation selected the event-based completion notification; Have 2 events, one for data, the other to cancel long send/recv:

then calling WSASend,

followed by

which is setup to return on any one event signaled. Now assume send is in progress, and m_hInterruptEvent is signaled. WSAWaitForMultipleEvents returns, technically the function calling send can return as well and delete internally allocated buffers.

What is not clear to me, the WSASend may still be working in background, and deleting buffers will cause data corruption in best case.

What would be the proper way to stop the background Send/Receive, if the socket needs to be used for something else immediately?

I looked at the CancelIO(), but the MSDN never mentions it in relation to Sockets, does it work with file based IO only?

0 投票
1 回答
66 浏览

winapi - 事件触发窗口消息

有没有办法在设置事件时生成窗口消息?我想设置一个重叠的 I/O 操作,所以它不会阻塞,但我不想轮询它的状态。我知道我可以使用线程,但我只需要它来执行此操作。似乎有更好的方法。

0 投票
0 回答
868 浏览

windows - Windows 中潜在的异步(重叠)I/O 实现

我想讨论 Windows 中潜在的异步(重叠)I/O 实现,因为有很多方法可以实现它。Windows 中的重叠 I/O 提供了异步处理数据的能力,即操作的执行是非阻塞的。

编辑:这个问题的目的一方面是讨论改进我自己的实现,另一方面是讨论替代实现。什么异步 I/O 实现在并行重 I/O 上最有意义,什么在小型单线程应用程序中最有意义。

我将引用MSDN

当一个函数被同步执行时,它在操作完成之前不会返回。这意味着调用线程的执行可以无限期地阻塞,同时等待耗时的操作完成。调用重叠操作的函数可以立即返回,即使操作尚未完成。这使得一个耗时的 I/O 操作可以在后台执行,而调用线程可以自由地执行其他任务。例如,单个线程可以在不同的句柄上同时执行 I/O 操作,甚至可以在同一个句柄上同时执行读写操作。

我假设读者熟悉重叠 I/O 的基本概念。

异步 I/O 的另一种解决方案是完成端口,但这不是本次讨论的主题。有关其他 I/O 概念的更多信息,请参见 MSDN“关于文件管理 > 输入和输出 (I/O) > I/O 概念

我想在这里展示我的(C/C++)实现并分享它以供讨论。

这是我的扩展 OVERLAPPED 结构,称为IoOperation

每次调用ReadFileWriteFile调用异步操作时都会创建此结构。该Handle字段应使用相应的设备/文件句柄进行初始化。Operation是一个用户定义的字段,它告诉我们调用了什么操作。该字段Buffer是指向先前分配的具有给定大小的内存块的指针BufferSize。当然,这个结构体可以随意扩展。它可以包含操作结果,实际传输的大小等。

我们需要的第一件事是每次完成重叠 I/O 时都会发出一个(自动重置)事件句柄。

首先,我决定对所有异步操作只使用一个事件。然后我决定用RegisterWaitForSingleObject的线程池线程注册这个事件。

因此,每次发出此事件信号时,WaitOrTimerCallback都会调用我的回调。

异步操作的初始化如下:

GetOverlappedResult每个操作都排队并在我的WaitOrTimerCallback回调中成功调用后被删除。代替new一直在这里调用,我们可以使用内存池来避免内存碎片并加快分配速度。

当然,为了多线程安全,我们在访问 I/O 队列时需要一个锁保护(临界区)。

这种实现方式有优点也有缺点。

优点

  • 在持久化线程池线程中执行,无需手动创建线程
  • 只需要一个事件
  • 每个操作都在一个 I/O 队列中排队(可以稍后调用 CancelIoEx)

缺点

  • I/O 队列需要额外的内存/cpu 时间
  • 对所有排队的 I/O 甚至未完成的 I/O 调用 GetOverlappedResult
0 投票
1 回答
4257 浏览

c++ - 具有重叠 I/O 的非阻塞套接字

我正在尝试通过套接字丛林工作,并遇到了具有重叠 I/O 的非阻塞套接字。我家里有三本书只提到了这个概念,但没有真正解释它或给我任何例子。

所以我要找的是一篇文章,其中用一个例子来解释这个get,或者只是一个我可以自己完成的例子。如果这适用于 Windows,那就太好了,但我想我也应该能够从 unix 传输它。

我不介意一本书作为资料来源,但我很乐意避免再花 50 美元。到目前为止,我只找到了非常基本的概念以及与其他插座模型的基本比较。并不是我不理解他们的概念,而是我希望看到他们在行动中,也许能很好地解释他们是如何工作的。(我根本不介意长篇文章:))

0 投票
4 回答
215 浏览

c++ - 使用与 c++ D'tor 重叠的 I/O 冲突

我正在编写一个单客户端(目前)服务器,该服务器具有一个主循环,可以中断客户端请求,并分配一个适当的处理程序。

对于某些任务,我想使用 MS 重叠 I/O(仅适用于 Windows)。在其中一个中,我想从文件中读取并将内容写入套接字。因为我有该动作的类包装,它分配一个缓冲区,文件的大小,然后调用 ReadFile (带有实际的文件系统文件),然后是一个 WriteFile (这次是一个套接字句柄) 两者都被重叠了。

问题是:因为它是异步的,所以会自动调用 d'tor 类,并且在工作完成之前释放文件的缓冲区,

显然,这是我的一个坏设计,我真的很想听听你的建议,

谢谢!

0 投票
4 回答
19292 浏览

linux - Linux 上真的没有异步块 I/O 吗?

考虑一个受 CPU 限制但也具有高性能 I/O 要求的应用程序。

我正在将 Linux 文件 I/O 与 Windows 进行比较,我根本看不出 epoll 将如何帮助 Linux 程序。内核会告诉我文件描述符“准备好读取”,但我仍然必须调用阻塞 read() 来获取我的数据,如果我想读取兆字节,很明显这会阻塞。

在 Windows 上,我可以创建一个设置了 OVERLAPPED 的文件句柄,然后使用非阻塞 I/O,并在 I/O 完成时收到通知,并使用该完成函数中的数据。我不需要花费应用程序级的挂钟时间来等待数据,这意味着我可以将线程数精确调整到我的内核数,并获得 100% 的有效 CPU 利用率。

如果我必须在 Linux 上模拟异步 I/O,那么我必须分配一些线程来执行此操作,而这些线程将花费一些时间来处理 CPU 的事情,并且会花费大量时间阻塞 I/O,另外,与这些线程之间的消息传递也会产生开销。因此,我将过度订阅或未充分利用我的 CPU 内核。

我将 mmap() + madvise() (WILLNEED) 视为“穷人的异步 I/O”,但它仍然没有到达那里,因为完成后我无法收到通知——我有“猜”,如果我猜“错”了,我最终会阻塞内存访问,等待数据来自磁盘。

Linux 似乎在 io_submit 中有异步 I/O 的开始,而且它似乎也有一个用户空间 POSIX aio 实现,但是这种方式已经有一段时间了,我知道没有人会为这些系统的关键性担保, 高性能应用。

Windows 模型的工作原理大致如下:

  1. 发出异步操作。
  2. 将异步操作绑定到特定的 I/O 完成端口。
  3. 等待该端口上的操作完成
  4. 当 I/O 完成时,等待端口的线程解除阻塞,并返回对挂起的 I/O 操作的引用。

步骤 1/2 通常作为一件事情完成。步骤 3/4 通常使用工作线程池完成,而不是(必然)与发出 I/O 的线程相同。这个模型有点类似于 boost::asio 提供的模型,除了 boost::asio 实际上并没有给你异步的基于块的(磁盘)I/O。

与 Linux 中的 epoll 不同的是,在第 4 步中,还没有发生任何 I/O——它将第 1 步提升到第 4 步之后,如果您已经确切知道自己需要什么,那么这是“倒退”。

在编写了大量嵌入式、桌面和服务器操作系统之后,我可以说这种异步 I/O 模型对于某些类型的程序来说是非常自然的。它也是非常高吞吐量和低开销的。我认为这是 Linux I/O 模型在 API 级别上剩下的真正缺点之一。