Windows核心编程笔记:同步设备I/O与异步设备I/O 0409

同步设备I/O与异步设备I/O

异步设备I/O基础

以异步的方式来访问设备,必须先调用CreateFile,并在dwFlagsAndAttributes参数中指定FILE_FLAG_OVERLAPPED标志来打开设备。这个标志告诉系统我们想要以异步的方式来访问设备。

为了将I/O请求加入设备驱动程序的队列中,必须使用ReadFileWriteFile函数.

BOOL ReadFile(
  HANDLE hFile,
  PVOID pvBuffer,
  DWORD nNumBytesToRead,
  PDWORD pdwNumBytes,
  OVERLAPPED* pOverlapped
);

BOOL WriteFile(
  HANDLE hFile,
  CONST VOID *pvBuffer
  DWORD nNumBytesToWrite,
  PWORD pdwNumBytes,
  OVERLAPPED* pOverlapped
);

当我们使用这两个函数中的任何一个时函数会检查hFile参数标志的设备是否是用FILE_FLAG_OVERLAPPED标志打开的。如果打开设备时指定了这个标志,那么函数会执行异步设备I/O


OVERLAPPED结构

定义:

typedef struct _OVERLAPPED{
    DWORD    Internal; //[out] Error code
    DWORD    InternalHigh; //[out] Number of bytes transferred
    DWORD    Offset;    //[in] Low 32-bit file offset
    DWORD    OffsetHigh; //[in] High 32-bit file offset
    HANDLE    hEvent;//[in] Event handle or data
}

后三个成员必须在调用ReadFileWriteFile之前进行初始化。另外两个成员由驱动程序设置。

OffsetOffsetHigh

这两个成员构成一个64位的偏移量,它表示当访问文件的时候应该从哪里开始进行I/O操作。

在执行异步I/O的时候,系统会忽略文件指针。

hEvent成员

用来接收I/O完成通知的4中方法中,其中一种方法会用到这个成员。当使用可提醒I/O通知函数时,可以根据需要来使用这个成员。

Internal成员

这个成员用来保存已处理的I/O请求的错误码。一旦发出一个异步I/O请求,设备驱动程序会立即将Internal设为STATUS_PENDING,表示没有错误,因为操作尚未开始。

WinBase.h中定义的HasOverlappedIoCompleted宏允许我们检查一个异步I/O操作是否已经完成。如果请求还在等待状态,那么该宏会返回FALSE。如果I/O请求已经完成,那么该宏会返回TRUE

#define HasOverlappedIoCompleted(pOverlapped) \

((pOverlapped)->internal != STATUS_PENDING)

InternalHigh成员

当异步I/O请求完成时,这个成员用来保存已传输的字节数。


异步设备I/O的注意事项

1.设备驱动程序不必以先入先出的方式来处理队列中的I/O请求。如果不按顺序来执行I/O请求能够提高性能,那么设备驱动程序一般都会这样做;

2,驱动程序总是会以同步的方式来执行某些操作,如NTFS文件的压缩、增大文件的长度、向文件追加信息等。要想进一步了解那些始终都以同步方式执行的操作,参阅http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B156932

3.在异步I/O请求完成之前,一定不能移动或是销毁在发出I/O请求时所使用的数据缓存和OVERLAPPED结构。

一个错误的例子:

VOID ReadData(HANDLE hFile){

OVERLAPPED = {0};

BYTE b[100];

ReadFile(hFile, b, 100, NULL,&o);

}

4.必须为每个I/O请求分配并初始化一个不同的OVERLAPPED结构。


取消队列中的设备I/O请求

1.调用CancelIo来取消由给定句柄所标志的线程添加到队列中的所有I/O请求(除非该句柄具有与之相关联的I/O完成端口)

BOOL CancelIo(HANDLE hFile);

2.关闭设备句柄,来取消已经添加到队列中的所有I/O请求,而不管它们是由哪个线程添加的。

3.当线程终止时,系统会自动取消该线程发出的所有I/O请求,但如果请求被发往的设备句柄具有与之相关联的I/O完成端口,那么它们不在被取消之列;

4.将发往给定文件句柄的一个指定的I/O请求取消:

BOOL CancelIoEx(HANDLE hFile,LPOVERLAPPED pOverlapped);

使用CancelIoEx,我们能够将调用线程之外的其它线程发出的待处理的I/O请求取消。这个函数会将hFile设备的待处理的I/O请求中所有与pOverlapped参数相关联的请求请求都标记为已取消。如果pOverlappedNULL,那么CancelIoEx会将hFile指定的设备的所有待处理I/O请求都取消。

猜你喜欢

转载自www.cnblogs.com/Toya/p/12666393.html