IOCP是一种典型的异步IO设计范式,简单的说就是当发起一个IO操作后,不等待操作结束就立刻返回,IO操作的结果在另外一个队列上得到通知并回调。 异步IO本身并不是一种高级的东西。相反的,在操作系统底层,所有的IO请求都是异步发起的,然后通过中断处理对结果进行处理,中断是一种在硬件层面上的 回调机制。因为异步IO在编程上相当困难,特别是对于那些不具备高级特性的语言来说。所以在设计操作系统时,设计师会将这些底层IO的复杂性封装起来,抽 象成容易使用的同步IO调用供上层使用。同步IO的意思是IO操作发起后,调用会等待IO操作结束才返回结果(阻塞模式),或者当IO不能立刻完成时返回 错误(非阻塞模式),同时再提供一种查询机制(Select模式),告诉用户当前的IO可执行状态 ,通常我们会用Reactor模式将Select封装起来,将用户主动查询变成事件回调(这不影响Select查询的本质)。而IOCP则将底层的IO复杂性暴露出来,还原出IO异步性的本质,这实际上是一种抽象的倒退,因此IOCP是一种复杂的编程模型。
在我看来,IOCP其实就是一个任务队列,一个线程安全并且最高效维持这种安全性的队列,把一些待处理任务的信息放入队列,可以有多个线程从这队列中获取不同的任务,并发处理,以达到高效的目的。一般的多线程处理当任务分配下来时就创建一个线程来处理,处理完毕就结束线程(用消息队列可以避免重复创建结束,但是必须要程序定向分配,不容易知道任务是否结束,或者代价较高),这样CPU在无用的判断上花了许多时间,效率自然不高。IOCP模型就没有这样的问题,线程不必重启,空闲了就去取任务处理,没任务了就休眠。所以这种模型适合编写各种"池"。
【基本操作】
IOCP有个端口,可以看成一个队列对象,放入的任务信息为一个上下文(IO_CONTEXT,其中有个重叠结构OVERLAPPED 用于标识)。
/**********端口的创建、关联***************/
1 WINBASEAPI __out HANDLE WINAPI CreateIoCompletionPort( 2 __in HANDLE FileHandle, //关联的文件句柄。 3 __in_opt HANDLE ExistingCompletionPort, //已经存在的完成端口。如果为NULL,则为新建一个IOCP。 4 __in ULONG_PTR CompletionKey, //传送给处理函数的参数。 5 __in DWORD NumberOfConcurrentThreads //有多少个线程在访问这个消息队列。当参数不为0的时候,
系统忽略该参数,当该参数为0表示允许同时相等数目于
处理器个数的线程访问该消息队列。 6 );
/**********向队列中加入任务***************/
1 BOOL PostQueuedCompletionStatus( 2 HANDLE CompletlonPort, //指定想向其发送一个完成数据包的完成端口对象 3 DW0RD dwNumberOfBytesTrlansferred, //指定—个值,直接传递给GetQueuedCompletionStatus函数中对应的参数 4 DWORD dwCompletlonKey, //指定—个值,直接传递给GetQueuedCompletionStatus函数中对应的参数 5 LPOVERLAPPED lpoverlapped, //指定—个值,直接传递给GetQueuedCompletionStatus函数中对应的参数 6 );
/**********从队列中获取任务***************/
1 BOOL GetQueuedCompletionStatus 2 ( 3 HANDLE CompletionPort, \\指定的IOCP,该值由CreateIoCompletionPort函数创建。 4 LPDWORD lpNumberOfBytes, \\一次完成后的I/O操作所传送数据的字节数(dwNumberOfBytesTrlansferred)。 5 PULONG_PTR lpCompletionKey, \\当文件I/O操作完成后,用于存放与之关联的CK。 6 LPOVERLAPPED *lpOverlapped, \\为调用IOCP机制所引用的OVERLAPPED结构。 7 DWORD dwMilliseconds \\用于指定调用者等待CP的时间。 8 );
但是毕竟是异步编程,多线程处理还是要考虑很多问题的