同步和重叠输入和输出

可以在文件、命名管道和串行通信设备上执行同步或异步 (也称为重叠) I/O 操作。 WriteFileReadFileDeviceIoControlWaitCommEventConnectNamedPipeTransactNamedPipe 函数可以同步或异步执行。 ReadFileExWriteFileEx 函数只能异步执行。

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

若要将其执行与重叠操作的完成同步,调用线程使用 GetOverlappedResult 函数、 GetOverlappedResultEx 函数或 等待函数 之一来确定重叠操作何时完成。 还可以使用 HasOverlappedIoCompleted 宏轮询完成。

若要取消所有挂起的异步 I/O 操作,请使用 CancelIoEx 函数并提供用于指定要取消的请求的 OVERLAPPED 结构。 使用 CancelIo 函数可取消由指定文件句柄的调用线程发出的挂起异步 I/O 操作。

重叠操作需要使用 FILE_FLAG_OVERLAPPED 标志创建的文件、命名管道或通信设备。 当线程调用函数 ((如 ReadFile 函数) )来执行重叠操作时,调用线程必须指定指向 OVERLAPPED 结构的指针。 (如果此指针为 NULL,则函数返回值可能会错误地指示操作已完成。) 除非使用事件来指示 I/O 操作完成,否则 必须将 OVERLAPPED 结构的所有成员初始化为零。 如果使用事件,则 OVERLAPPED 结构的 hEvent 成员将指定已分配事件对象的句柄。 当对 I/O 函数的调用在操作完成之前返回时,系统会将事件对象的状态设置为非签名。 系统将事件对象的状态设置为在操作完成时发出信号。 仅当同时有多个未完成的 I/O 操作时,才需要事件。 如果未使用事件,则每个已完成的 I/O 操作都将向文件、命名管道或通信设备发出信号。

调用函数以执行重叠操作时,该操作可能在函数返回之前完成。 发生这种情况时,将像同步执行操作一样处理结果。 但是,如果操作未完成,则函数的返回值为 FALSEGetLastError 函数返回 ERROR_IO_PENDING

线程可以通过以下两种方法之一管理重叠操作:

  • 使用 GetOverlappedResultGetOverlappedResultEx 函数等待重叠操作完成。 如果使用 GetOverlappedResultEx ,则调用线程可以为重叠操作指定超时,或执行可发出警报的等待。
  • 在其中一个等待函数中指定 OVERLAPPED 结构的手动重置事件对象的句柄,然后在等待函数返回后调用 GetOverlappedResultGetOverlappedResultEx。 函数返回已完成的重叠操作的结果,对于适合此类信息的函数,它将报告已传输的实际字节数。

在单个线程上同时执行多个重叠操作时,调用线程必须为每个操作指定 OVERLAPPED 结构。 每个 OVERLAPPED 结构必须指定不同手动重置事件对象的句柄。 为了等待任何一个重叠的操作完成,线程会将所有手动重置事件句柄指定为其中一个多对象 等待函数中的等待条件。 多对象等待函数的返回值指示向哪个手动重置事件对象发出信号,以便线程可以确定哪个重叠操作导致等待操作完成。

对每个重叠操作使用单独的事件对象更安全,而不是不指定任何事件对象或将同一事件对象用于多个操作。 如果未在 OVERLAPPED 结构中指定任何事件对象,则当重叠操作完成时,系统会向文件、命名管道或通信设备的状态发出信号。 因此,可以在等待函数中将这些句柄指定为同步对象,尽管它们用于此目的可能难以管理,因为在同一文件、命名管道或通信设备上同时执行重叠操作时,无法知道哪个操作导致对象状态被发出信号。

线程不应重复使用某个事件,前提是该事件仅由该线程的重叠操作发出信号。 事件在与正在完成的重叠操作相同的线程上发出信号。 在多个线程上使用相同的事件可能会导致争用条件,在该条件下,对于操作首先完成的线程,对于使用该事件的其他线程,该事件会正确发出事件信号。 然后,在下一个重叠操作完成时,将针对使用该事件的所有线程再次向事件发出信号,依此进行,直到所有重叠操作完成。

有关说明如何使用重叠操作、完成例程和 GetOverlappedResult 函数的示例,请参阅 使用管道

Windows Vista、Windows Server 2003 和 Windows XP:

重用 重叠 结构时要小心。 如果在多个线程上重复使用 OVERLAPPED 结构,并在 bWait 参数设置为 TRUE 的情况下调用 GetOverlappedResult,则调用线程必须确保在重用结构之前发出关联的事件信号。 这可以通过在调用 GetOverlappedResult 后使用 WaitForSingleObject 函数来强制线程等待操作完成。 请注意,事件对象必须是手动重置事件对象。 如果使用 autoreset 事件对象,则调用将 bWait 参数设置为 TRUEGetOverlappedResult 会导致无限期阻止该函数。 对于在应用程序清单中将 Windows 7 指定为支持的操作系统的应用程序,从 Windows 7 和 Windows Server 2008 R2 开始,此行为发生了变化。 有关详细信息,请参阅 应用程序清单

I/O 概念