《Windows via C/C++》学习笔记 —— 设备I/O之“同步的设备I/O”

  前面曾经讲过,设备I/O的方式有两种:同步和异步。本篇介绍一下同步设备I/O。主要涉及到两个函数:ReadFile和WriteFile。

  不要被这两个函数的名称迷惑,不仅可以将这两个作用于文件,也可以作用于其他设备:比如管道、邮槽等。

 

  最简单的设备I/O,可以通过ReadFile和WriteFile这两个函数来实现:

BOOL ReadFile(
   HANDLE      hFile,         
// 设备对象句柄
   PVOID       pvBuffer,       // 读取缓冲区
   DWORD       nNumBytesToRead,      // 读取的字节数
   PDWORD      pdwNumBytes,          // 返回实际读取的字节数
   OVERLAPPED *  pOverlapped);         // 重叠结构指针,仅在异步方式有用
BOOL WriteFile(
   HANDLE      hFile,
   CONST VOID  
* pvBuffer,
   DWORD       nNumBytesToWrite,
   PDWORD      pdwNumBytes,     
// 返回实际写入的字节数
   OVERLAPPED *  pOverlapped);

 

  在同步方式下使用这2个函数进行设备I/O,在同步模式下,两个函数的最后一个参数pOverlapped都要设置为NULL。另外,必须要注意这一点:就是在用CreateFile创建或打开设备之时,其FLAG参数不能包括FLAG_FILE_OVERLAPPED,否则系统认为你想要异步地实现设备I/O。

  另外,ReadFile只能读取这些设备,即在使用CreateFile创建或打开设备的时候,该函数的FLAG参数中包括GENERIC_READ。而WriteFile只能写入这些设备,即使用CreateFile函数的时候,FLAG参数包括GENERIC_WRITE。

 

  邮槽、管道、文件、串行端口等设备是有自己的高速缓存的。如果在CreateFile函数的FLAG参数中没有包括FILE_FLAG_NO_BUFFERING,也就是可以将写入的数据暂存在缓冲区中,那么可以通过FlushFileBuffers来强行将暂存在与设备有关的缓冲区中的全部数据写入到设备中。

BOOL FlushFileBuffers(HANDLE hFile);

 

  同步方式的设备I/O实现简单,但是缺点也是明显的,就是会阻碍有关线程中的其他与设备I/O无关的操作。因为设备I/O函数直到设备I/O请求结束才返回,如果数据量大,很可能会阻碍其他无关的操作。

  为了解决这个问题,你应该尽量使用异步的设备I/O。但是可惜的是,Windows API中,没有为CreaetFile这个函数提供任何异步的方式来实现。Windows Vista提供了另一种方法:中途取消同步设备I/O。可以通过使用函数CancelSynchronousIo来取消一个线程之内的正在进行的同步设备I/O操作。

BOOL CancelSynchronousIo(HANDLE hThread);      // 参数是线程句柄

 

  该函数接受一个线程句柄,该句柄是一个正在等待同步设备I/O操作完成的线程的句柄。该句柄在创建或打开的时候,必须具有THREAD_TERMINATE操作权限。如果你调用CreateThread或_beginthreadex函数来创建线程,那么返回的线程句柄就包含THREAD_TERMINATED的操作权限。如果使用OpenThread函数来获得一个已创建的线程的句柄,那么就传递THREAD_TERMINATED给dwDesiredAccess参数(第1个参数)。如果没有设置该权限,那么CancelSynchronousIo返回FALSE,调用GetLastError返回ERROR_ACCESS_DENIED(访问拒绝错误)。

  如果线程已经结束了等待设备I/O,那么再调用CancelSynchronousIo函数会返回TRUE,而不是FLASE,调用GetLastError则返回ERROR_OPERATION_ABORTED(操作失败错误)。

  如果线程并不是等待在设备I/O的返回上,那么调用该函数会返回FALSE,随后调用GetLastError会返回ERROR_NO_FOUND(未找到的错误)。

 

你可能感兴趣的:(windows)