可提醒I/O

 

  平时在编写程序时,我们经常会遇到设备I/O操作问题。一般的来说,对于具有小量数据或者速度快的设备进行I/O操作时,我们可以使用同步I/O的方法来读写数据。但是,如果要读取大容量的设备或者访问设备时间较长时,实行异步I/O操作可以确保我们的程序不会因为同步I/O等待而无法响应其他的工作。

  那么,异步I/O操作是如何告知应用程序I/O操作应经完成的呢?一般来说,有4中方法:

  1. 触发设备内核对象
  2. 触发事件内核对象
  3. 可提醒I/O
  4. I/O完成端口

  下面,我主要将以下第三种方法:可提醒I/O。

    我们知道,系统创建一个线程的时候,会创建一个与线程相关联的队列,我们称之为APC(异步调用过程)队列。这个队列到底是用来干嘛的呢?要知道,Microsoft从来不会做无聊的事(假设^_^)。当我们发出一个I/O请求(ReadFileEx)时,如果在该请求函数参数中指定了完成函数(也可以说是回调函数)的地址,那么首先该请求将这个完成函数的地址告知设备驱动程序,当设备驱动程序处理完I/O请求时,又将该地址以及要传给回调函数的值归为一项放到线程的APC队列中(APC里面放的什么东东,现在我们终于知道啦)。然后,如果线程是可提醒状态,那么他会从APC队列中取出一项来处理(也就是,调用完成函数),处理完后,如果APC不为空,继续处理,直至为空,之后可提醒函数的调用返回。通常,我们用6个可提醒函数将线程设为可提醒态。

   从上面的描述中,我们不难得知,为了实现可提醒I/O,我们必须建一个回调函数,但是由于这些函数没有与某个问题有关的信息,所以我们无法针对某类问题做更多的处理,为此,我们可能得为不同的请求建立不同的回调函数,这无疑增加了程序的复杂性;其次,我们的每一个线程发出请求的处理也是由该线程来实施的,如果一个线程发出多个请求,那么APC的调用却是一个接着一个,效率上也不是太高。这两点影响了可提醒I/O的发展。

   除了由设备驱动程序添加APC项外,Windows也允许我们手动地添加一项到APC队列中。

   说的都是理论的东西,大家不容易理解,所以,请看下面的一个实例:

#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>

//Asynchronizing procedure call function 
VOID CALLBACK APCFun(ULONG_PTR dwParam)
{
	//Do nothing
	printf("APC fuction is called.....\n");
}

UINT WINAPI  ThreadFunc (PVOID  pvParam) 
{
	HANDLE  hEvent = (HANDLE)pvParam;


	//Wait in an alertable state so that we can be forced to exit cleanly
	printf("Wait for the event object....\n");
	DWORD dw = WaitForSingleObjectEx(hEvent, INFINITE, TRUE);

	printf("last error is : %d\n",GetLastError());
	printf("Thread quits wait state.....\n");
	//The event is signaled
	if (dw == WAIT_OBJECT_0)
	{
		printf("The event object is signaled....\n");
	}

	//APC is called
	if (dw == WAIT_IO_COMPLETION )
	{
		printf("Thread quits the wait state because a APC is put in the thread's queue....\n");
		return 0;
	}
	return 0;
}


void main()
{

	//Create a event kernel object , auto-reset, nonsignaled
	HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
	HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, (PVOID)hEvent, 0, NULL);
	Sleep(300);
	QueueUserAPC(APCFun, hThread, NULL);

	//Wait for the thread to exit
	printf("Wait for the thread to exit....\n");
	WaitForSingleObject(hThread, INFINITE);
	CloseHandle(hEvent);
	CloseHandle(hThread);
	getchar();
}

结果如下:
   

   上述代码和结果截图具有自解释性,我就不罗嗦啦,请自己对照MSDN好好理解。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值