2

CancelIo()应该取消与调用线程相关的所有挂起的 I/O 操作。根据我的经验,CancelIo() 有时也会取消未来的I/O 操作。鉴于:

ReadFile(port, buffer, length, &bytesTransferred, overlapped);
  1. CancelIo(port)如果我在读取之前立即调用,GetQueuedCompletionStatus()将永远阻塞,永远不会收到读取操作。
  2. CancelIo(port)如果我在读取后立即调用,GetQueuedCompletionStatus()将返回 0GetLastError()==ERROR_OPERATION_ABORTED
  3. 如果我调用CancelIo(port)并且没有挂起或后续读取,GetQueuedCompletionStatus()将永远阻塞。

这里的关键点是无法检测何时CancelIo()完成执行。如何确保CancelIo()已完成执行并且发出进一步的读取请求是安全的?

PS:查看http://osdir.com/ml/lib.boost.asio.user/2008-02/msg00074.htmlhttp://www.boost.org/doc/libs/1_44_0/doc/html/ boost_asio/using.html听起来 CancelIo() 并不是真的可用。必须客户需要 Windows XP 支持。我有哪些选择?

注意:我正在从串行端口读取。

4

4 回答 4

3

CancelIo()工作正常。我误解了我的代码。

经过进一步调查,事实证明代码正在调用,CancelIo()然后ReadFile()是 timeout INFINITE。完成端口从未收到读取通知,因为远程端从未发送任何内容。也就是说,CancelIo()没有取消后续操作。

我在这里找到了一些令人大开眼界的文档:

为异步 I/O 编码时要小心,因为系统保留在需要时使操作同步的权利。因此,最好编写程序以正确处理可能同步或异步完成的 I/O 操作。示例代码演示了这种考虑。

事实证明,如果正在读取的数据已被设备驱动程序缓存,则设备驱动程序可能会选择以同步方式处理异步操作。经过进一步调查,我发现在CancelIo()被调用之前ReadFile()它有时会导致后者同步返回。我不知道为什么完成端口在ReadFile()之后从未收到通知,CancelIo()但我无法再重现此问题。

无论ReadFile()是同步还是异步,都会发出完成端口的信号。

于 2010-10-16T21:30:31.950 回答
2

等待(可能超时为零)overlapped.Handle。将设置操作是完成还是取消。

于 2010-10-13T06:13:03.383 回答
-1

可以编写没有 CancelIo 函数的异步 I/O 代码。问题取决于您使用 CancelIO 的场景。假设您需要实现文件读取线程。线程伪代码:

为了(;;)
{
    ReadFile(端口, 缓冲区, 长度, &bytesTransferred, 重叠);
    WaitForMultipleObjects(重叠事件+停止事件);

    如果(停止事件发出信号)
       休息;

    如果(重叠的事件发出信号)
        处理 ReadFile 结果
}

此类线程使用重叠 I/O 读取文件(套接字、端口等)。大多数时候它在 WiatForMultipleObjects 线上等待。它在有新数据可用或发出停止事件信号时唤醒。要停止此线程,请从另一个线程设置停止事件。不使用 CancelIO。

于 2010-10-13T06:20:07.033 回答
-1

如果您已经在使用重叠操作,为什么还需要取消 I/O?“取消”运行中的 I/O 操作的整个概念非常容易竞争,并且完全受制于您尝试写入的底层设备堆栈;实际上,您唯一想要这样做的就是解除对等待该 I/O 完成的另一个线程的阻塞。

于 2010-10-13T17:58:46.753 回答