Win平台高级编程:异步I/O,Asynchronous I/O serial functions

 *    1  CancelIo                     Cancels all pending I/O operations that are issued by the calling thread for a specified file handle.
 *    2  CancelIoEx                   Marks all pending I/O operations for the specified file handle in the current process as canceled, regardless of which thread created the I/O operation.
 *    3  CancelSynchronousIo          Marks pending synchronous I/O operations that are issued by the specified thread as canceled.
 *    4  GetOverlappedResult          Retrieves the results of an overlapped operation.
 *    5  ReadFile                     Reads data from a file, starting at the position that is indicated by a file pointer. This function can operate synchronously and asynchronously.
 *    6  WriteFile                    Writes data to a file at a position that a file pointer specifies. This function can operate synchronously and asynchronously.
 *

  ReadFile, 读取文件。
   主要参数:1. 异步I/O句柄。
             5. 指针,函数用来储存Overlapped结构,设置事件对象,读取的起始地址(Offset)。
  WriteFile, 写文件。
   主要参数:1. 异步I/O句柄。
             5. 指针,Overlapped结构,储存文件操作信息,设置事件对象,写入的起始地址(Offset)。
  GetOverlappedResult, 获得异步I/O操作状态或等待一个I/O执行完成。
  CancelSynchronousIo, 发送一个自定义的I/O操作到完成端口队列,它的参数对应到GetQueuedCompletionStatus接收函数
   主要参数:1.异步I/O句柄
  CancelIo, 取消当前进程中某一个或全部正在执行中的异步I/O操作。
   主要参数:1. 异步I/O句柄
             2. OVERLAPPED结构,指定的I/O操作。
  CancelIoEx, 取消当前线程中所有进行中的异步I/O操作。
   主要参数:1. 异步I/O句柄

 

#include <stdio.h>
#include <windows.h>

// WARNING !!!  All list items must be aligned on a MEMORY_ALLOCATION_ALIGNMENT boundary;
// WARNING !!!  otherwise, this function will behave unpredictably.
#define MAX_THREADS 5

#define ERR_MSG(m)                            \
  if (!PrintMessage(GetLastError(), NULL))    \
    fprintf(stderr, m);

#define FATAL_ERROR(m)                        \
  {                                           \
    ERR_MSG(m)                                \
    goto Exception;                           \
  }

volatile BOOL bLoop;

BYTE
  buffer_demo[1024];

DWORD
  dwOperate,
  dwBytesXfreed;

HANDLE
  hEventIo;

BOOL
PrintMessage(errorId, format)
  long errorId;
  char *format;
{
  LPSTR
    text = NULL;

  DWORD
    length;

  // Gets the message string by an error code.
  length = FormatMessage(
    FORMAT_MESSAGE_ALLOCATE_BUFFER |
    FORMAT_MESSAGE_FROM_SYSTEM |
    FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL, errorId, 0,
    (LPSTR)&text,
    0, NULL);

  if (length == 0)
  {
    fprintf(stderr, "FormatMessage was failed, error:0x%08x, format:0x%08x\n", GetLastError(), errorId);
    return FALSE;
  }

  if (format != NULL)
    fprintf(stderr, format, text);
  else
    fprintf(stderr, text);

  // Free the buffer allocate by the FormatMessage function.
  LocalFree(text);

  return TRUE;
}

DWORD WINAPI
pfnProcThread(data)
  LPVOID data;
{
  HANDLE
    hFile = (HANDLE)data;

  DWORD
    error,
    transferred;

  BOOL
    bResult = FALSE;

  OVERLAPPED
    overlap;

  while (TRUE)
  {
    WaitForSingleObject(hEventIo, INFINITE);
    if (!bLoop)
      break;

    /* GetOverlappedResult
      Parameters
        hFile [in]
          A handle to the file, named pipe, or communications device. This is the same handle that was specified when the
          overlapped operation was started by a call to below functions
            1 ReadFile
            2 WriteFile
            3 ConnectNamedPipe
            4 TransactNamedPipe
            5 DeviceIoControl
            6 WaitCommEvent

        lpOverlapped [in]
          A pointer to an OVERLAPPED structure that was specified when the overlapped operation was started.

        lpNumberOfBytesTransferred [out]
          A pointer to a variable that receives the number of bytes that were actually transferred by a read or write operation.
          For a TransactNamedPipe operation, this is the number of bytes that were read from the pipe. For a DeviceIoControl operation,
          this is the number of bytes of output data returned by the device driver. For a ConnectNamedPipe or WaitCommEvent operation,
          this value is undefined.

        bWait [in]
          If this parameter is TRUE, the function does not return until the operation has been completed. If this parameter is FALSE and
          the operation is still pending, the function returns FALSE and the GetLastError function returns ERROR_IO_INCOMPLETE.

      Return Value
        If the function succeeds, the return value is nonzero.
        If the function fails, the return value is zero. To get extended error information, call GetLastError.

      Remarks
        The results reported by the GetOverlappedResult function are those of the specified handle's last overlapped operation to which
        the specified OVERLAPPED structure was provided, and for which the operation's results were pending. A pending operation is indicated
        when the function that started the operation returns FALSE, and the GetLastError function returns ERROR_IO_PENDING. When an I/O
        operation is pending, the function that started the operation resets the hEvent member of the OVERLAPPED structure to the nonsignaled
        state. Then when the pending operation has been completed, the system sets the event object to the signaled state. Specify a manual-reset
        event object in the OVERLAPPED structure. If an auto-reset event object is used, the event handle must not be specified in any other wait
        operation in the interval between starting the overlapped operation and the call to GetOverlappedResult. For example, the event object is
        sometimes specified in one of the wait functions to wait for the operation's completion. When the wait function returns, the system sets
        an auto-reset event's state to nonsignaled, and a subsequent call to GetOverlappedResult with the bWait parameter set to TRUE causes the
        function to be blocked indefinitely. If the bWait parameter is TRUE, GetOverlappedResult determines whether the pending operation has
        been completed by waiting for the event object to be in the signaled state. If the hEvent member of the OVERLAPPED structure is NULL,
        the system uses the state of the hFile handle to signal when the operation has been completed. Use of file, named pipe, or
        communications-device handles for this purpose is discouraged. It is safer to use an event object because of the confusion that can
        occur when multiple simultaneous overlapped operations are performed on the same file, named pipe, or communications device. In this
        situation, there is no way to know which operation caused the object's state to be signaled.
     */
    if (GetOverlappedResult(hFile, &overlap, &transferred, FALSE))
    {
      if (dwOperate == 0)
        fprintf(stdout, "READ  COMPLETED T %04X, D %04d, K %04d\n", GetCurrentThreadId(), transferred, dwBytesXfreed);
      else
        fprintf(stdout, "WRITE COMPLETED T %04X, D %04d, K %04d\n", GetCurrentThreadId(), transferred, dwBytesXfreed);
    }
    else
    {
      switch (error = GetLastError())
      {
      case ERROR_HANDLE_EOF:
        fprintf(stdout, "GetOverlappedResult found EOF\n");
        break;
      case ERROR_IO_INCOMPLETE:
        fprintf(stdout, "GetOverlappedResult I/O Incomplete\n");
        break;
      default:
        fprintf(stdout, "GetOverlappedResult I/O unknown error %d\n", error);
      }
    }

    ResetEvent(hEventIo);
    Sleep(100);
  }

  fprintf(stdout, "Thread %04X was exited.\n", GetCurrentThreadId());
  return 0;
}

BOOL
WaitForUserKeyInput(key, exitkey, keydown)
  LPDWORD key;
  DWORD exitkey;
  BOOL keydown;
{
  DWORD
    length;

  INPUT_RECORD
    record;

  *key = -1;
  if (!ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &record, 1, &length) ||
      !length)
  {
    ERR_MSG("Failed to get user key input.");
    Sleep(100);
    // 读取键盘输入失败,返回TRUE进入下一个读取动作。
    return TRUE;
  }

  if (record.EventType != KEY_EVENT ||
     !(keydown ? record.Event.KeyEvent.bKeyDown: !record.Event.KeyEvent.bKeyDown))
    return TRUE;

  // 返回当前KEY值。
  *key = record.Event.KeyEvent.wVirtualKeyCode;

  // 如果是指定的退出按键或ESC则返回FALSE。
  return !(*key == exitkey || *key == VK_ESCAPE);
}

int
main()
{
  DWORD
    i;

  HANDLE
    hFile = NULL,
    hThread = NULL;

  INPUT_RECORD
    record;

  OVERLAPPED
    overlap;

  CHAR
    szFilePath[MAX_PATH];

  GetModuleFileName(NULL, szFilePath, MAX_PATH);
  i = strlen(szFilePath);
  while (szFilePath[--i] != '\\');
  strcpy(&szFilePath[i], "\\data.dat");

  hFile = CreateFile(szFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED, NULL);
  if (hFile == INVALID_HANDLE_VALUE)
    FATAL_ERROR("Failed to create test file.\n");

  hEventIo = CreateEvent(NULL, TRUE, FALSE, "MyEvent1");
  if (hEventIo == NULL)
    FATAL_ERROR("Failed to create event object.\n");

  bLoop = TRUE;
  hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)pfnProcThread, (LPVOID)hFile, 0, NULL);
  if (hThread == NULL)
    FATAL_ERROR("Failed to create thread object.\n");

  RtlFillMemory(buffer_demo, 1024, 52);
  ZeroMemory(&overlap, sizeof(OVERLAPPED));
  overlap.hEvent = hEventIo;

  while (WaitForUserKeyInput(&i, VK_RETURN, TRUE))
  {
    switch (i)
    {
    case VK_UP:
      dwOperate = 0;
      /*
        OVERLAPPED structure used for ReadFile function.
        If hFile is opened with FILE_FLAG_OVERLAPPED, the lpOverlapped parameter must point to a valid and unique OVERLAPPED
        structure, otherwise the function can incorrectly report that the read operation is complete. For an hFile that supports
        byte offsets, if you use this parameter you must specify a byte offset at which to start reading from the file or device.
        This offset is specified by setting the Offset and OffsetHigh members of the OVERLAPPED structure. For an hFile that does
        not support byte offsets, Offset and OffsetHigh are ignored.
       */
      overlap.Offset = 0;
      overlap.OffsetHigh = 0;
      ReadFile(hFile, buffer_demo, 1024, &dwBytesXfreed, &overlap);
      i = GetLastError();
      if (i != ERROR_IO_PENDING)
        PrintMessage(i);
      break;
    case VK_DOWN:
      dwOperate = 1;
      /*
        OVERLAPPED structure used for WriteFile function.
        For an hFile that supports byte offsets, if you use this parameter you must specify a byte offset at which to start
        writing to the file or device. This offset is specified by setting the Offset and OffsetHigh members of the OVERLAPPED
        structure. For an hFile that does not support byte offsets, Offset and OffsetHigh are ignored. To write to the end of
        file, specify both the Offset and OffsetHigh members of the OVERLAPPED structure as 0xFFFFFFFF. This is functionally
        equivalent to previously calling the CreateFile function to open hFile using FILE_APPEND_DATA access.
       */
      overlap.Offset = 0xFFFFFFFF;
      overlap.OffsetHigh = 0xFFFFFFFF;
      WriteFile(hFile, buffer_demo, 1024, &dwBytesXfreed, &overlap);
      i = GetLastError();
      if (i != ERROR_IO_PENDING)
        PrintMessage(i);
      break;
    case VK_LEFT:
      if (!CancelIo(hFile))
        ERR_MSG("Failed to cancel the I/O operations.");
      break;
    case VK_RIGHT:
      break;
    }
  }

  bLoop = FALSE;

  // PulseEvent(hEventIo);
  // Ensure that the event object is the signed status.
  SetEvent(hEventIo);
  WaitForSingleObject(hThread, INFINITE);

Exception:
  if (hThread)
  {
    CloseHandle(hThread);
    hThread = NULL;
  }

  if (hEventIo)
    CloseHandle(hEventIo);

  if (hFile && hFile != INVALID_HANDLE_VALUE)
    CloseHandle(hFile);

  return 0;
}


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值