异步设备I/O--请求加入队列与接受完成通知

异步I/O请求:  当线程发出一个异步I/O请求时,这个请求被传递给设备驱动程序,由后者负责完成实际的I/O操作。 当驱动程序在等待设备响应的时候,应用程序的线程并没有因为等待I/O请求完成而被挂起,线程会继续运行并执行其他任务。
 
将异步I/O请求加入队列,有驱动程序完成对列中 I/O 请求的处理,并通知应用程序I/O操作已完成。
异步方式访问设备:
CreateFile(,,,) 在dwFlagsAndAttributes参数指定FILE_FLAG_OVERLAPPED标志来打开设备,告诉其用异步的方式访问设备。
将I/O请求加入到设备驱动程序的队列:
通过调用ReadFile, WriteFile 函数(会检测 设备文件是否标记了 FILE_FLAG_OVERLAPPED,若标记 则 异步,否则同步)将I/O请求放入队列。
 
重叠结构(OVERLAPPED):
执行异步设备I/O的时候,需为pOverlapped参数传递一个已初始化的OVERLAPPED结构.
“overlapped”意思是执行I/O请求的时间与线程执行其他任务的时间是重叠的。
typedef struct _OVERLAPPED {
  DWORD Internal;                //[out] error code
  DWORD InternalHigh;       //[out] number of bytes transferred
  DWORD Offset;                  //[int]  low 32it offset
  DWORD OffsetHigh;         //[int]  high 32it offset
  HANDLE hEvent;               //[int]  evernt handle or data
  } OVERLAPPED, *LPOVERLAPPED;

其中offset OffsetHigh 用于 表明访问文件应从哪里开始I/O操作。 每个文件内核对象都有与之相关的文件指针,用于表明读取起始位置。每次操作完成后,os会自动更新文件指针。
同步I/O时 会接着上次的文件指针,异步I/O 无先后顺序,所以需指明其实偏移量。
异步I/O请求完成时,后收到一个OVERLAPPED结构的地址,及请求时的那个。有时为了获取更多的返回信息(如发送请求使用的设备句柄),这时可以对OVERLAPPED封装为C++类,使其能携带更多的信息。
 
异步设备I/O注意事项:
1. 驱动程序不必以先入先出的方式来处理队列中的I/O请求
OVERLAPPED o1 = {0};
OVERLAPPED o2 = {0};
BYTE bBuffer[100];
ReadFile ( hFile, bBuffer, 100, NULL, &o1 );
WriteFile ( hFile, bBuffer, 100, NULL, &o2 );
驱动程序可能先写 后读取。
提高效率为准:例 为了降低磁头的移动和寻道时间。寻找物理磁盘上相邻的请求。
 
2.用正确的方式检错
请求I/O 以同步方式执行时, ReadFile ,WriteFile 会返回非零值。  异步方式时,出错时 返回False, 需GetLastError判断,是出错还是 加入了队列,为处理完ERROR_IO_PENDING。

3.请求完成之前 不能移动或销毁发出的 数据缓存和OVERLAPPED结构
必须为每一个I/O请求 分配并初始化一个不同的OVERLAPPED结构
 
取消队列中的设备I/O请求:
BOOL CancelIoEx ( HANDLE hFile, LPOVERLAPPED poverlapped);    poverlapped为NULL时,取消hFile上所有I/O请求
 
接受I/O请求完成通知
Windows提供4中不同方式来接受完成通知
技术简介
触发设备内核对象
一个线程发出I/O请求,另一个线程出结果进行处理。
当向一个设备同时发出多个I/O请示时,则无能为力。因为设备只有一个,其处于激发状态与否,只能表示一个请求的状态。
触发事件内核对象
一个线程发出I/O请求,另一个线程出结果进行处理。
可以向一个设备同时发出多个I/O请求(为每个请求建立相应的事件对象)
使用可提醒I/O可以向一个设备同时发出多个I/O请求,发出请求的线程处理结果
使用I/O完成端口
一个线程发出I/O请求,另一个线程出结果进行处理。
可以向一个设备同时发出多个I/O请求
 
例:
1.
触发设备内核对象
HANDLE hFile = CreateFile(..., FILE_FLAG_OVERLAPPED, ...);
BYTE bBuffer[100];
OVERLAPPED o = {0};
o.Offset = 345;
 
bool bReadDone = ReadFile(hFile, bBuffer, 100, NULL, &o);
DWORD dwError = GetLastError();
 
if (!bReadDone && (dwError == ERROR_IO_PENDING))
{//waiting for it to complete
    WaitForSingleObject(hFile, INFINITE);  //挂起,等待完成请求,此时  驱动程序会将 设备内核设为触发状态
    bReadDone = TRUE;
}
if(bReadDone)
{
    //finished
}
else
{
    //error occurred; See dwError
}


 
2.触发事件内核对象
当对一个设备同时进行多个异步I/O请求时,必须为每个请求创建不同的事件对象,并将OVERLAPPED结构的最后一个成员hEven 初始化为一个事件内核对象。然后发送请求--ReadFile, WriteFile
当需要检测I/O请求的完成状态时,可以通过调用WaitForMultipleObjects,并传入相关联的时间句柄 即可。
HANDLE hFile = CreateFile(..., FILE_FLAG_OVERLAPPED, ...);
 
BYTE bReadBuffer[100];
OVERLAPPED oRead = {0};
o.Offset = 0;
oRead.hEvent = CreateEvent(...);
ReadFile(hFile, bReadBuffer, 100, NULL, &oRead);
 
BYTE bWriteBuffer[100] = {......};
OVERLAPPED oWrite = {0};
o.Offset = 0;
oWrite.hEvent = CreateEvent(...);
WriteFile(hFile, bReadBuffer, _countof(bWriteBuffer), NULL, &oWrite);
....
 
HANDLE h[2];
h[0] = oRead.hEvent;
h[1] = oWrite.hEvent;
DWORD dw = WaitForMultipleObjects( 2, h, FALSE, INFINITE);
switch(dw - WAIT_OBJECT_0)
    case 0://Read completed
    {
        ....
        break;
    }
    case 1://write completed
    {
        ....
        break;
    }
}


 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值