zoukankan      html  css  js  c++  java
  • 第10章 同步设备I/O和异步设备I/O(2)_同步IO和异步IO基础

    10.3 执行同步设备I/O

    (1)对设备读写操作的函数

      ①ReadFile/WriteFile函数

    参数

    描述

    hFile

    文件句柄

    pvBuffer

    指向要接收文件数据的缓冲区或把缓冲区数据写入设备

    nNumbytesToRead

    要读取的字节数或写入的字节数

    pdwNumBytes

    实际读取的字节数或写入的字节数

    pOverlapped

    指向OVERLAPPED结构体。

    ①要进行同步读写时,该参数为NULL,同时打开设备的时候,标志不能指定为FILE_FLAG_OVERLAPPED。

    ②要进行异步读写时,须指定该参数,同时打开设备时设置FILE_FLAG_OVERLAPPED标志。此时,函数不再等待,会直接返回FALSE,通过用GetLastError将得到ERROR_IO_PENDING

    返回值

    成功——非0。如果dwNumBytes=0,表示文件指针超过文件未尾。

    失败——FALSE。如果是异步调用,也返回FALSE,可通过GetLastError获得更详细的信息。

     【说明】

      ①要进行同步和异步的设置与最后一个参数pOverlapped的密切相关

      ②ReadFile只能用于哪些用GENERIC_READ打开的设备,同理WriteFile只能用于那些用GENERIC_WRITE标志打开的设备

    (2)将数据刷新到设备

      ①在CreateFile函数时可通过传FILE_FLAG_NO_BUFFERING等标志来决定是否对数据进行缓存

      ②如果要强制将缓存数据写入设备可调用FlushFileBuffers函数,但要注意该设备要用GENERIC_WRITE标志打开。

    (3)同步I/O的取消——CancelSynchronousIo(Vista以上版本才支持)

      ①与Read/WriteFile不同,CreateFile函数本身不能进行异步调用。如果等待时间太长,可以通过CancelSynchronousIo(hThread)来强制取消同步I/O操作并退出等待。

      ②参数hTread是由于等待同步I/O请求完成而被挂起的线程,这个句柄必须使用THREAD_TERMINATE访问权限创建,否则调用CancelSynchronousIo函数会失败。

      ③当调用CreateThread或_beginthreadex创建线程时,如果安全属性设为NULL,那么默认的权限是THREAD_IMPERSONATE

      ④当线程因等待同步I/O而被挂起,如果使用CancelSynchronousIo唤醒该线程,并取消同步操作。同时返回TRUE,但GetLastError将返回ERROR_OPERATION_ABORTED。

      ⑤调用CancelSynchronousIo的线程并不知道要唤醒的另一个线程目前的状态,如果这时另一个线程并不是因为要等待设备应被挂起,那么CancelSyncronousIo会返回FALSE,这时GetLastError将得到ERROR_NOT_FOUND。

    10.4 异步设备I/0基础

    10.4.1 OVERLAPPED结构

    (1)异步访问设备的方法

      ①先将CreateFile函数里的dwFlagsAndAttributes中指定为FILE_FLAG_OVERLAPPED标志,以告诉系统我们要以异步的方式来打开设备,以便后继的访问。

      ②调用Read/WriteFile并设置pOverlapped参数,将I/O请求包加入设备驱动程序的队列中。(注意,I/O请求包被发往驱动程序的队列。完成端口的队列是用来接收I/O完成包,也就是说它们是两个不同的队列特别是当设备关联了完成端口以后很容易混淆!)。

    (2)OVERLAPPED结构体

    字段

    描述

    DWORD Internal

    [out]出错代码

    ①当我们发出异步I/O请求时,会被设为STATUS_PENDING,表示没有错误,操作即将开始(或尚未开始),也叫作请求还处在等待状态。

    ②可用HasOverlappedIoComplete(pOverlapped)宏来检查是否还在等待状态。

    DWORD InternalHigh

    [out]己传输的字节数。当异步I/O请求完成时,用来保存己传输的字节数。

    DWORD Offset

    DWORD OffsetHigh

    [in]文件指针,偏移(分别是低32位和高32位),表示访问文件时从哪里开始进行I/O操作。

    ①设置异步时,会忽略文件内核对象的文件指针,因为那是给同步操作使用的

    ②非文件设备会忽略OffSet和OffSetHigh,但初始化时仍须指定为0

    HANDLE hEvent

    [in]事件句柄或自定义C++对象的地址,用来接收I/O完成时的通知。(见后面的分析)

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

    (1)设备驱动程序不必以先入先出的方式来处理队列中的I/O请求。这是因为在执行I/O请求时,为了提高性能(如降低磁头的移动和寻道时间,文件系统的驱动程序可能会在I/O请求队列中寻找那些要访问的位置在物理硬盘中相邻的请求)。

       ReadFile(hFile,bBuffer,100,NULL,&o1); //读请求先入列,并不一定先被处理。

       WriteFile(hFile,bBuffer,100,NULL,&o2);//写请求后入列,也可能被先处理。

    (2)错误的检查

      ①异步I/O以同步方式执行

        A、由于存在高速缓存,当试图将一个异步I/O请求入列时,设备驱动程序可能会直接从缓存中获取数据,而无需将I/O请求入列,这叫同步方式来执行该操作。

        B、同步方式执行时,Read/WriteFile这时己经从缓存中获得数据,会返回成功(非零)

      ②异步I/O以异步方式执行错误时会返回FALSE,GetLastError得到的常见错误如下

    错误码

    描述

    ERROR_IO_PENDING

    I/O请求己经被成功加入到了队列,会在晚些时候完成(其实并没错误产生)

    ERROR_INVALID_USER_BUFFER

    ERROR_NOT_ENOUGH_MEMORY

    I/O队列列表己满。新I/O请求无法加入队列。

    ERROR_NOT_ENOUGH_QUOTA

    (Quota限额的意思)

    某些设备要求将我们的数据缓存所在的存储器页面锁定,这样当I/O在等待处理的时候,数据不会被换出内存系统对一个进程能够锁定的存储器页面数量是有做了限制,如果在该进程线程中调用的Read/WriteFile要锁定的那缓存超过限制,就会返回FALSE。这里可以调用SetProcessWorkingSetSize给进程增加配额。

    (3)异步I/O请求完成之前,一定不能移动或销毁发出I/O请求时所使用的Buffer和OVERLAPPED结构体。如下以的代码是错误的。

    void ReadData(HANDLE hFile){
    
      OVERLAPPED ol={0};
    
      BYTE b[100];
    
      ReadFile(hFile,b,
    100,NULL,&ol); //异步调用。结构体ol和缓存b是局部变量,被销毁。但I/O请求完成后,驱动程序并没意识到ReadData己经返回,会修改ol和b指向的栈内存,从而破坏那里的数据。 }

    10.4.3 取消队列中的设备I/O请求——在I/O请求加入队列后,处理前将其取消

    (1)CancelIo(hFile)取消由调用该函数的线程发往hFile这个设备的所有I/O请求。(除非设备己经关联到I/O完成端口,因为这时I/O请求被发往的是完成端口的队列)。

    (2)关闭设备句柄(如CloseHandle(hFile)来取消己经添加到队列中的所有I/O请求。而不管这个I/O是哪个线程添加的。

    (3)当线程终止时,会自动取消该线程发出的所有I/O请求。但如果请求被发往的是I/O完成端口,那么它们不在被取消之列。

    (4)CancelIoEx(hFile,pOverlapped)可用来取消发往hFile设备的待处理I/O请求不管是哪个线程发往这个设备的),该函数每次只取消一条由pOverlapped指定的待处理请求,如果pOverlapped为NULL,则取消所有待处理的I/O请求

    ★被取消的I/O请求会导致Read/WriteFile失败,通过GetLastError时会返回错误码ERROR_OPERATION_ABORTED

  • 相关阅读:
    【Todo】各种语言里面的for循环 & loop
    git/icode操作记录
    UVA 639 (13.08.25)
    TkinterGUI
    [置顶] think in java interview-高级开发人员面试宝典(七)
    通过memcached来实现对tomcat集群中Session的共享策略
    Hibernate 配置详解(7)
    python模块之bsddb: bdb高性能嵌入式数据库 1.基础知识
    Python基础
    Objective-C中NSArray和NSMutableArray的基本用法
  • 原文地址:https://www.cnblogs.com/5iedu/p/4764640.html
Copyright © 2011-2022 走看看