同步管道和重叠管道 I/O

ReadFileWriteFileTransactNamedPipe,以及 connectNamedPipe 函数可以同步或异步地对管道执行输入和输出作。 当函数同步运行时,它不会返回,直到它正在执行的作完成。 这意味着,在等待耗时的作完成时,可以无限期阻止调用线程的执行。 当函数异步运行时,即使作尚未完成,它也会立即返回。 这样,就可以在后台执行耗时的作,同时调用线程可以自由执行其他任务。

使用异步 I/O,管道服务器可以使用执行以下步骤的循环:

  1. 在调用等待函数时指定多个事件对象,并等待其中一个对象设置为信号状态。
  2. 使用 wait 函数的返回值来确定哪些重叠作已完成。
  3. 执行清理已完成的作所需的任务,并为该管道句柄启动下一个作。 这可以涉及为同一管道句柄启动另一个重叠的作。

重叠的作使一个管道可以同时读取和写入数据,使单个线程能够在多个管道句柄上执行同时 I/O作。 这使单线程管道服务器能够高效地处理与多个管道客户端的通信。 有关示例,请参阅 使用重叠 I/O 的命名管道服务器

若要使管道服务器使用同步作与多个客户端通信,它必须为每个管道客户端创建一个单独的线程,以便一个或多个线程可以在其他线程等待时运行。 有关使用同步作的多线程管道服务器的示例,请参阅 多线程管道服务器

启用异步作

ReadFileWriteFileTransactNamedPipeConnectNamedPipe 函数只能在为指定的管道句柄启用重叠模式并指定指向 OVERLAPPED 结构的有效指针时,才能异步执行。 如果 重叠 指针 NULL,则函数返回值可能会错误地指示作已完成。 因此,强烈建议创建具有FILE_FLAG_OVERLAPPED且需要异步行为的句柄,应始终指定有效的 重叠 结构。

指定的 重叠 结构的 hEvent 成员必须包含手动重置事件对象的句柄。 这是由 CreateEvent 函数创建的同步对象。 启动重叠作的线程使用事件对象来确定作何时完成。 在同一句柄上执行同步作时,不应使用管道句柄进行同步,因为无法知道哪个作的完成导致管道句柄发出信号。 对同一管道句柄执行同时作的唯一可靠方法是为每个作使用单独的 OVERLAPPED 结构及其自己的事件对象。 有关事件对象的详细信息,请参阅 同步

此外,可以使用 GetQueuedCompletionStatusGetQueuedCompletionStatusEx 函数完成重叠作时收到通知。 在这种情况下,无需在 OVERLAPPED 结构中分配手动重置事件,并且完成方式与异步读取或写入作相同的方式针对管道句柄进行。 有关详细信息,请参阅 I/O 完成端口

ReadFileWriteFileTransactNamedPipeConnectNamedPipe作时,会发生以下情况之一:

  • 如果函数返回时作完成,则返回值指示作的成功或失败。 如果发生错误,则返回值为零,GetLastError 函数返回除ERROR_IO_PENDING以外的其他内容。
  • 如果函数返回时作尚未完成,则返回值为零,GetLastError 返回ERROR_IO_PENDING。 在这种情况下,调用线程必须等待作完成。 然后,调用线程必须调用 GetOverlappedResult 函数来确定结果。

使用完成例程

ReadFileExWriteFileEx 函数提供另一种重叠 I/O 形式。 与重叠 ReadFileWriteFile 函数不同,后者使用事件对象来发出完成信号,扩展函数指定 完成例程。 完成例程是完成读取或写入作时排队执行的函数。 完成例程在调用 ReadFileExWriteFileEx 通过调用 fAlertable 参数设置为 true 可警报等待函数之一来启动可警报等待作。 在可警报的等待作中,当 ReadFileExWriteFileEx 完成例程排队执行时,函数也会返回。 管道服务器可以使用扩展函数为每个连接到它的客户端执行一系列读取和写入作。 序列中的每个读取或写入作指定完成例程,每个完成例程都会启动序列中的下一步。 有关示例,请参阅 使用完成例程的命名管道服务器