码迷,mamicode.com
首页 > 其他好文 > 详细

第10章 同步设备I/O和异步设备I/O(3)_I/O完成端口

时间:2015-08-28 12:25:33      阅读:132      评论:0      收藏:0      [点我收藏+]

标签:

10.5 接收I/O请求完成的通知

(1)I/O请求被加入设备驱动程序的队列,当请求完成以后,设备驱动也要负责通知我们I/O请求己经完成。

(2)可以用4种方法来接收I/O请求己经完成的通知

技术

特点

触发设备内核对象

①允许一个线程发出I/O请求,另一个线程对结果进行处理。

②当向一个设备同时发出多个I/O请求的时候,这种方法是不能用的,因为等待函数中等待的是同一个内核对象,只要任何一个I/O请求完成时都会被触发,却没办法区别是哪个请求的完成触发了内核对象。

触发事件内核对象

①允许一个线程发出I/O请求,另一个线程对结果进行处理。

②允许我们向一个设备同时发出多个I/O请求的时候。(因为每个请求都通过pOverlapped与一个事件相关联)

使用可警告I/O

①发出I/O请求的线程必须对结果进行处理,因为这是通过线程的APC队列来实现的,而APC队列是线程独有的。

②允许我们向一个设备同时发出多个I/O请求的时候。

使用I/O完成端口

①允许一个线程发出I/O请求,另一个线程对结果进行处理。

②允许我们向一个设备同时发出多个I/O请求的时候。

③这项技术具有高度的伸缩性和最佳的灵活性

10.5.1 通过触发设备内核对象来通知I/O处理己完成

(1)Read/WriteFile在将I/O请求添加到队列之前,会先将对象设为未触发状态。当设备驱动程序完成了请求之后,会将设备内核对象设为触发状态。

(2)使用这种方法不能达到异步调用的好处,因为发出请求以后,要立即等待请求的完成,这跟同步调用效果是一样的。

【示例代码】——在实际的代码中,用这种方式来获取通知,因为没能真正体现异步的好处,也不能处理多个I/O请求

//以异步方问访问hFile设备(传入参数FILE_FLAG_OVERLAPPED)
HANDLE hFile = CreateFile(..., FILE_FLAG_OVERLAPPED, ...);
BYTE bBuffer[100];
OVERLAPPED  o = { 0 };
o.Offset = 345; //从第346个字节开始读取数据

BOOL bReadDone = ReadFile(hFile, bBuffer, 100, NULL, &o); //添加异步I/O请求
DWORD dwError = GetLastError();

//ReadFile异步调用会立即,返回值为FALSE,GetLastError为ERROR_IO_PENDING表示
//请求正在被处理
if (!bReadDone && (dwError == ERROR_IO_PENDING)){
    //I/O请求正在被异步处理,等待I/O请求完成的通知
    WaitForSingleObject(hFile, INFINITE); //等待的是设备内核对象!
    bReadDone = TRUE;
}

if (bReadDone){
    //读取完成后,数据被写入bBuffer,状态信息写入pOverlapped结构体中
    //o.Internal包含IO错误代码
    //o.InternalHigh包含己经传输的字节数
    //bBuffer包含读取到的数据
} else{
    //出现错误,可查看dwError以获得更多信息
}

 【示例程序2】——用来说明设备内核对象不能处理多个IO请求

//以异步方问访问hFile设备(传入参数FILE_FLAG_OVERLAPPED)
HANDLE hFile = CreateFile(..., FILE_FLAG_OVERLAPPED, ...);

//异步I/O读请求
BYTE bReadBuffer[10];
OVERLAPPED  oRead = { 0 };
oRead.Offset = 0; 
ReadFile(hFile, bReadBuffer, 100, NULL, &o); //添加异步I/O读请求

//异步I/O写请求
BYTE bWriteBuffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
OVERLAPPED  oWrite = { 0 };
oWrite.Offset = 10;
WriteFile(hFile, bWriteBuffer,_countof(bWriteBuffer), NULL, &oWrite);

...
WaitForSingleObject(hFile, INFINITE); //hFile被触发可以是读操作完成或写完成。
//我们不知道为什么完成:读?写?或两者都是?

10.5.2 触发事件内核对象

(1)在每个I/O请求的OVERLAPPED结构体的hEvent创建一个用来监听该请求完成的事件对象。当一个异步I/O请求完成时,设备驱动程序会调用SetEvent来触发事件。

(2)驱动程序仍然会像从前一样,将设备对象也设为触发状态,因为己经有了可用的事件对象,所以可以通过SetFileCompletionNoticationModes(hFile,FILE_SKIP_SET_EVENT_ON_HANDLE)来告诉操作系统在操作完成时,不要触发文件对象。

(3)以下代码是故意那样设计的。实际应用中,可用一个循环来等待I/O请求完成。

【示例程序】——利用事件对象处理多个IO请求

//以异步方问访问hFile设备(传入参数FILE_FLAG_OVERLAPPED)
HANDLE hFile = CreateFile(..., FILE_FLAG_OVERLAPPED, ...);

//异步I/O读请求
BYTE bReadBuffer[10];
OVERLAPPED  oRead = { 0 };
oRead.Offset = 0;
oRead.hEvent = CreateEvent(...); //创建一个监听读的事件对象
ReadFile(hFile, bReadBuffer, 100, NULL, &o); //添加异步I/O读请求

//异步I/O写请求
BYTE bWriteBuffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
OVERLAPPED  oWrite = { 0 };
oWrite.Offset = 10;
oWrite.hEvent = CreateEvent(...);//创建一个监听写的事件对象
WriteFile(hFile, bWriteBuffer, _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: break;//读完成
    case 1: break;//写完成
}

 

第10章 同步设备I/O和异步设备I/O(3)_I/O完成端口

标签:

原文地址:http://www.cnblogs.com/5iedu/p/4765859.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!