• 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请求都取消。

  • 相关阅读:
    Java数组的内存结构
    2014.11.9--最近的小感悟
    十一两天感悟
    Are you happiness
    Are you busy?
    Lesson 81-82 Are they true
    Lesson 79-80 People are getting sick
    Lesson 77-78 Socially Discriminated Against
    Lesson 75-76 Shopping on the web
    更新单点,求区间—— luogu 3374
  • 原文地址:https://www.cnblogs.com/Toya/p/12666393.html
Copyright © 2020-2023  润新知