重叠I/O

OVERLAPPED数据结构

Windows操作系统API的头文件minwinbase.h（包含在windows.h）中，定义了数据结构：
typedef struct _OVERLAPPED { // o 
    DWORD  Internal;        //通常被保留。当GetOverlappedResult()的参数bWait为真且字段Internal为STATUS_PENDING，GetOverlappedResult()被阻塞直至重叠操作完成。当GetOverlappedResult()返回False并且GatLastError()返回ERROR_IO_INCOMPLETE时，重叠操作尚未完成。
    DWORD  InternalHigh;    //通常被保留，当GetOverlappedResult()传回False时，为被传输数据的长度。
    DWORD  Offset;            //指定文件的位置,从该位置传送数据,文件位置是相对文件开始处的字节偏移量。调用 ReadFile或WriteFile函数之前调用进程设置这个成员，读写命名管道及通信设备时调用进程忽略这个成员;
    DWORD  OffsetHigh;      //指定开始传送数据的字节偏移量的高位字,读写命名管道及通信设备时调用进程忽略这个成员;
    HANDLE hEvent;            //发起同步操作的函数应把该事件设为nonsignaled状态；pending操作完成时，操作系统把该事件设为signaled状态    } OVERLAPPED, *LPOVERLAPPED;
数据结构OVERLAPPED的用途：每个重叠操作使用了自己的OVERLAPPED数据结构对象，可用于区别这些重叠操作。应用程序往往在一块内存的前部用作OVERLAPPED数据结构，紧随其后的是与具体重叠操作有关的输入输出数据。OVERLAPPED和数据缓冲区，只有在重叠操作完成之后，才可以释放；否则会造成进程崩溃。

示例

按照重叠I/O模式打开一个文件（或其他I/O控制端，如命名管道），注意必须用FILE_FLAG_OVERLAPPED标志：
HANDLE hFile;

   hFile = CreateFile(szFileName,
                      GENERIC_READ,
                      0,
                      NULL,
                      OPEN_EXISTING,
                      FILE_FLAG_NORMAL | FILE_FLAG_OVERLAPPED,
                      NULL);

   if (hFile == INVALID_HANDLE_VALUE)
      ErrorOpeningFile();
使用重叠I/O的Windows API函数，如ReadFile(), WriteFile(), Winsock的WSASend()与WSARecv()需要传递一个结构OVERLAPPED作为函数参数，函数调用后立即返回。由操作系统在后台完成I/O操作。需要注意的是，一个OVERLAPPED结构对象在它绑定的重叠I/O还没有完成前，绝对不能被用户程序修改其值或者重用，也不能释放其所用内存（如果它是函数局部变量那么这个函数不能退出以免局部变量所用的运行栈被卷回(unwinding))。因为操作系统使用OVERLAPPED来区别同一个文件句柄下的可能多个未完成的不同的重叠I/O。同样，重叠I/O完成之前，它的数据缓冲区也决不能被程序读写。
if (!ReadFile(hFile,
                 pDataBuf,
                 dwSizeOfBuffer,
                 &NumberOfBytesRead,  //接收I/O操作完成的字节数，对于重叠I/O这个输出值无意义
                 &osReadOperation )   //OVERLAPPED结构
   {//如果函数返回false，表示IO操作没有立即全部执行完
      if (GetLastError() != ERROR_IO_PENDING)
      {
         // Some other error occurred while reading the file.
         ErrorReadingFile();
         ExitProcess(0);
      }
      else
         // Operation has been queued and
         // will complete in the future.
         fOverlapped = TRUE;
   }
   else
      // Operation has completed immediately.
  // 即使作为重叠I/O提交的请求，仍然有可能被操作系统按照同步方式执行完IO操作，这时不应该再去GetOverlappedResult或WaitForSingleObject
      fOverlapped = FALSE;

   if (fOverlapped)
   {
      // Wait for the operation to complete before continuing.
      // You could do some background work if you wanted to.
      if (GetOverlappedResult( hFile,
                               &osReadOperation,
                               &NumberOfBytesTransferred, //接收I/O操作完成的字节数
                               TRUE))//该参数为true将阻塞该线程等待IO操作完成
         ReadHasCompleted(NumberOfBytesTransferred);
      else
         // Operation has completed, but it failed.
         ErrorReadingFile();
   }
   else
      ReadHasCompleted(NumberOfBytesRead);