IOCP 原理 代码
名词解释IOCP简介四-Read

hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
该语句的作用是返回一个句柄,在为完成端口分配了一个套接字句柄后,用来对那个 端口进行标定(引用)。
函数功能:注意该函数实际用于两个明显有别的目的: 1. 用于创建一个完成端口对象。 2. 将一个句柄同完成端口关联到一起。
IOCP简介
IOCP的开发
1、CreateIoCompletionPort
最开始创建一个完成端口时,唯一感兴趣的参数便是 NumberOfConcurrentThreads(并发线程的数量);前面三个参数都会被忽略。 NumberOfConcurrentThreads参数的特殊之处在于,它定义了在一个完成端口上, 同时允许执行的线程数量。理想情况下,我们希望每个处理器各自负责一个线程的运 行,为完成端口提供服务,避免过于频繁的线程“场景”切换。若将该参数设为0Байду номын сангаас 表明系统内安装了多少个处理器,便允许同时运行多少个线程!可用下述代码创建一 个I/O完成端口:
IOCP简介
IOCP的应用
可以看出完成端口是到目前为止最为复杂的输入输出模式。然而,当一个 应用不得不同时处理大量的socket时,它也提供了使系统性能达到最佳的可 能性。只有在被迫面对几百甚至几千个并发的socket、你又希望在添加CPU 后可以获得更好的scale时,才被派上战场。关于完成端口,最重要的是记住 这一点:如果你为winnt/2000开发处理大量socket I/O 请求的高性能服 务,它是你的最佳选择 IOCP不仅仅在通信socket上,同时也可以用于其他方面,例如读写文件, 比如把文件句柄关联到完成端口上,产生一定量的工作器线程,读取文件不同 的部分实际读取数据是系统内部处理,只是读取完了通知一下,并且把相关I O数据填充到结构体中
iocp 编程

IOCP编程什么是IOCPIOCP(Input/Output Completion Ports)是一种高效的异步I/O模型,它在Windows操作系统中提供了对网络编程的支持。
通过使用IOCP,我们可以实现高性能、可伸缩性强的网络应用程序。
在传统的同步I/O模型中,当一个线程在等待数据时,它会被阻塞,直到数据到达。
而在异步I/O模型中,线程不会被阻塞,它可以继续执行其他任务。
IOCP就是基于这种异步I/O模型实现的。
IOCP的工作原理使用IOCP进行编程主要涉及以下几个核心概念:端口(Port)、完成包(Completion Packet)、套接字(Socket)和重叠操作(Overlapped Operation)。
•端口:一个端口代表一个I/O设备或者一个文件。
每个端口都有一个关联的完成端口。
•完成包:完成包是指一个I/O操作完成时所生成的信息块。
它包含了完成的状态、相关参数和返回值等信息。
•套接字:套接字是网络编程中用于进行通信的抽象概念。
•重叠操作:重叠操作是指一次I/O操作请求,在请求发出之后,线程就可以继续执行其他任务了。
IOCP主要通过以下几个步骤来实现异步I/O:1.创建一个完成端口(Completion Port)。
2.创建一个或多个工作者线程(Worker Thread),这些线程用于处理I/O操作。
3.将套接字关联到完成端口上,使得该套接字上的I/O操作能够被异步处理。
4.当有I/O操作完成时,系统会将相关的完成包放入完成队列中。
5.工作者线程从完成队列中获取完成包,并进行相应的处理。
IOCP的优势和适用场景相比于传统的同步阻塞模型,IOCP具有以下几个优势:1.高性能:IOCP能够充分利用CPU资源,提高程序的并发处理能力。
它通过异步I/O模型,使得线程在等待数据时不被阻塞,可以继续执行其他任务,从而充分利用了CPU资源。
2.可伸缩性:IOCP可以轻松地扩展到支持大量的并发连接。
C++Socket编程—socket网络模型之IOCP

C++Socket编程—socket⽹络模型之IOCP⽹络模型—IOCP模型⼀. 什么是IOCP?什么是IOCP模型?IOCP模型有什么作⽤?1) IOCP(I/O Completion Port),常称I/O完成端⼝。
2) IOCP模型属于⼀种通讯模型,适⽤于(能控制并发执⾏的)⾼负载服务器的⼀个技术,适⽤于⼤型项⽬,处理⾼并发问题。
3) 通俗⼀点说,就是⽤于⾼效处理很多很多的客户端进⾏数据交换的⼀个模型。
4) 或者可以说,就是能异步I/O操作的模型。
⼆. IOCP ⼯作机制尽管select、WSAA、WSAE这些socket通信模型可以让我们不⽤开更多的线程来处理每⼀连接,但它们收发数据时仍然要调⽤Recv和Send,Recv和Send实际上仍然会与操作系统底层进⾏交互,仍然会进⼊内核,所以还是会有效率上的损失。
IOCP怎么解决这个问题呢?IOCP有⼀个队列,当你要发数据时,收数据和连接时,都交由IOCP队列处理,不会与操作系统底层交互。
发送数据时,先将缓冲区和长度封好,这个请求会发送到IOCP队列,IOCP内部会帮你把请求发出去。
收数据时,收数据的请求丢掉IOCP队列,IOCP会将收到的数据填⼊指定的缓冲区⾥边,当数据收好后会通知你来收数据。
建⽴连接时,IOCP帮你把连接建⽴好,告诉你新的连接已经来了。
开发者使⽤IOCP时⽆需关注数据收、发、连接,只需关注处理数据三. IOCP的存在理由(IOCP的优点)及技术相关有哪些?IOCP是⽤于⾼效处理很多很多的客户端进⾏数据交换的⼀个模型,那么,它具体的优点有些什么呢?它到底⽤到了哪些技术了呢?在Windows环境下⼜如何去使⽤这些技术来编程呢?它主要使⽤上哪些API函数呢?1) 使⽤IOCP模型编程的优点①帮助维持重复使⽤的内存池。
(与重叠I/O技术有关)②去除删除线程创建/终结负担。
③利于管理,分配线程,控制并发,最⼩化的线程上下⽂切换。
简述iocp模型的原理和工作过程

简述iocp模型的原理和工作过程IOCP模型的原理和工作过程如下:原理:IOCP模型的核心原理是利用操作系统提供的异步I/O和内核级事件通知机制。
异步I/O使得应用程序可以在等待I/O完成时继续处理其他任务,而内核级事件通知机制可以使得操作系统在I/O完成后主动通知应用程序。
通过将I/O操作的处理放在操作系统层面,IOCP模型能够实现高并发、高吞吐量的网络通信。
工作过程:1.创建IOCP对象:应用程序首先创建一个IOCP对象,用于和操作系统进行通信。
2.绑定套接字:应用程序将要进行异步I/O操作的套接字与IOCP对象进行关联。
3.接受连接:应用程序使用套接字进行监听,并且接受到客户端连接请求后,将连接套接字与IOCP对象进行关联,从而使得这个连接套接字能够参与IOCP模型的异步I/O操作。
4.发送和接收数据:应用程序通过调用操作系统提供的异步I/O操作函数,发起网络数据的发送和接收操作。
在发送和接收操作完成之前,应用程序可以继续处理其他任务。
5.等待通知:在发送和接收操作完成之后,应用程序会调用一个等待通知的函数,将自己挂起,等待操作系统的通知。
6.I/O完成通知:当操作系统中发生I/O操作完成的事件时,IOCP对象会通知应用程序,并将I/O操作的结果返回给应用程序。
7.处理完成的I/O操作:应用程序在收到I/O完成的通知后,可以根据返回的结果进行相应的处理。
通常会将I/O操作的结果放入一个队列中,以便后续的处理。
8.处理队列中的完成操作:应用程序会不断地从队列中取出已完成的I/O操作,并进行相应的处理。
处理完成的操作后,应用程序可以继续发起新的I/O操作,从而实现不断地进行网络通信。
总结:IOCP模型利用操作系统提供的异步I/O和内核级事件通知机制,将网络通信的I/O操作交给操作系统来处理,从而实现了高并发、高吞吐量的网络通信。
应用程序通过调用操作系统提供的异步I/O函数来发起发送和接收数据的操作,在操作完成前可以继续处理其他任务。
IOCP

完成IO使用总结IOCP(I/O Completion Port,I/O完成端口)是性能最好的一种I/O模型。
它是应用程序使用线程池处理异步I/O请求的一种机制。
在处理多个并发的异步I/O请求时,以往的模型都是在接收请求是创建一个线程来应答请求。
这样就有很多的线程并行地运行在系统中。
而这些线程都是可运行的,Windows内核花费大量的时间在进行线程的上下文切换,并没有多少时间花在线程运行上。
再加上创建新线程的开销比较大,所以造成了效率的低下。
调用的步骤如下:抽象出一个完成端口大概的处理流程:1:创建一个完成端口。
2:创建一个线程A。
3:A线程循环调用GetQueuedCompletionStatus()函数来得到IO操作结果,这个函数是个阻塞函数。
4:主线程循环里调用accept等待客户端连接上来。
5:主线程里accept返回新连接建立以后,把这个新的套接字句柄用CreateIoCompletionPort 关联到完成端口,然后发出一个异步的WSASend或者WSARecv调用,因为是异步函数,WSASend/WSARecv会马上返回,实际的发送或者接收数据的操作由WINDOWS系统去做。
6:主线程继续下一次循环,阻塞在accept这里等待客户端连接。
7:WINDOWS系统完成WSASend或者WSArecv的操作,把结果发到完成端口。
8:A线程里的GetQueuedCompletionStatus()马上返回,并从完成端口取得刚完成的WSASend/WSARecv的结果。
9:在A线程里对这些数据进行处理(如果处理过程很耗时,需要新开线程处理),然后接着发出WSASend/WSARecv,并继续下一次循环阻塞在GetQueuedCompletionStatus()这里。
归根到底概括完成端口模型一句话:我们不停地发出异步的WSASend/WSARecv IO操作,具体的IO处理过程由WINDOWS系统完成,WINDOWS系统完成实际的IO处理后,把结果送到完成端口上(如果有多个IO 都完成了,那么就在完成端口那里排成一个队列)。
iocp_2_重叠异步IO

IOCP(完成端口)是什么以下就是IOCP的模型图,能看懂么?IOCP模型(图1.1)IOCP是什么IOCP模型相对于其它模型(select,。
),确实有点复杂。
它虽然就那么几个I/O操作函数,但它们都有一大串的参数,返回值的多样性,大大的加大了理解难度。
但是如果你理解了它,掌握了难点重点,也就那么一回事。
可以从以下几方理解什么是IOCP。
一、IOCP的实现步骤。
二、IOCP的核心--重叠异步I/O。
三、如何提交I/O请求。
四、如何取得I/O返回的操作结果,并作处理。
五、IOCP的一个完整例子。
< 二>重叠异步I/O重叠异步I/O要点:1.驱动原理2.VOERLAPPED 结构的作用3.OVERLAPPED 结构的扩展和应用1.重叠异步I/O的驱动原理IOCP的核心就是重叠异步I/O。
首先理解它的工作原理,什么是重叠异步I/O呢?重叠异步I/O的原理是:客户(应用程序)向I/O管理器提交I/O操作(读或写数据)请求,然后去忙其它事。
I/O操作完成之后,I/O管理器再通知客户。
同样,IOCP就是socket向I/O管理器提交各种请求,然后等待并取得I/O管理器返回的结果,如图1.1 所示。
IOCP就像你去银行办理业务,先去取个号码,然后等待叫号。
在拿到号码到被叫号期间,你可以干什么都行(IOCP和叫号还是有点区别的,就是IOCP会保留结果直到被取走,而叫号在叫到你的号码时,你不在,那么你的号码就作废了)。
也可以这么理解重叠异步I/O,就是在一头提交I/O请求(可以一次或多次—叫重叠),然后再另一头取得I/O操作的结果。
这两个操作是不同时、不连续的,这就是异步的原因。
2.VOERLAPPED 结构的作用提交I/O请求的socket函数有:ConnectEx、AcceptEx、WSASend、WSARecv。
取得I/O操作返回结果的函数有:GetQueuedCompletionStatus,GetOverlappedResult 等。
iocp流程

iocp流程I/O Completion Port (IOCP) 是 Windows 系统提供的一种高效的 I/O 模型,可以大大提高网络编程的效率和性能。
在分析 IOCP 流程之前,首先要了解 IOCP 的一些基本原理和用法。
IOCP 基本原理IOCP 的基本原理是通过 CreateIoCompletionPort 函数创建一个 I/O 完成端口句柄,将相关的操作(如异步 I/O 操作)关联到该句柄上,并通过 GetQueuedCompletionStatus 函数等待 I/O 完成事件的发生,当事件发生后,系统会自动调用已经与完成端口关联的回调函数来处理该事件。
IOCP 使用步骤下面是使用 IOCP 模型进行网络编程的基本步骤:1. 创建 I/O 完成端口句柄使用 CreateIoCompletionPort 函数创建一个 I/O 完成端口句柄,并指定线程池大小(ThreadCount),通常设置为处理器数量的两倍或三倍,具体根据实际情况进行调整,以提高并发处理能力。
2. 创建套接字并绑定到 I/O 完成端口使用 socket 函数创建一个网络套接字,并将其绑定到 I/O 完成端口句柄上,以便在套接字上的 I/O 操作完成时能够自动通知 I/O 完成端口。
3. 提交 I/O 操作使用 WSARecv 和 WSASend 等函数提交 I/O 操作,将 I/O 操作相关的参数(如套接字句柄、缓冲区、长度等)传递给函数,函数会马上返回,操作会在后台异步执行。
4. 获取 I/O 完成事件使用 GetQueuedCompletionStatus 函数从 I/O 完成端口句柄上获取I/O 完成事件,并将相关的参数(如套接字句柄、缓冲区、长度等)传递给回调函数,回调函数会根据事件类型进行相应的处理(如接收数据或发送数据)。
5. 处理 I/O 完成事件在回调函数中,根据写操作或是读操作的不同,调用相应的函数(如WSASend 或 WSARecv)处理 I/O 完成事件,并提交下一轮 I/O 操作,以便继续异步执行。
IOCP完全解析

DWORD Flags = 0; // 单 I/O 操作数据 LPPER_IO_DATA PerIoData = NULL; PerIoData = (LPPER_IO_DATA)GlobalAlloc(GPTR, sizeof(PER_IO_DATA)); ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED)); PerIoData->DataBuf.len = 1024; PerIoData->DataBuf.buf = PerIoData->buffer; PerIoData->OperationType = 0; // read WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags, &(PerIoData->Overlapped), NULL); } /**/////////////////////////////////////////////////////////////////////////// return nRetCode; } /**/////////////////////////////////////////////////////////////////////////// DWORD WINAPI ServerWorkerThread(LPVOID lpParam) { HANDLE CompletionPort = (HANDLE)lpParam; DWORD BytesTransferred; LPOVERLAPPED lpOverlapped; LPPER_HANDLE_DATA PerHandleData = NULL; LPPER_IO_DATA PerIoData = NULL; DWORD SendBytes; DWORD RecvBytes; DWORD Flags; BOOL bRet = FALSE; while (TRUE) { bRet = GetQueuedCompletionStatus(CompletionPort, &BytesTransferred, (PULONG_PTR) &PerHandleData,
SpringIOC和SpringAOP的实现原理(源码主线流程)

SpringIOC和SpringAOP的实现原理(源码主线流程)写在前⾯正本⽂参考了《spring技术内幕》和spring 4.0.5源码。
本⽂只描述原理流程的主线部分,其他⽐如验证,缓存什么可以具体参考源码理解。
Spring IOC⼀、容器初始化容器的初始化⾸先是在对应的构造器中进⾏,在applicationContext的实现类构造器中,⾸先对参数路径中的${}进⾏了处理,⽤系统变量替换(setConfigLocations⽅法)然后调⽤refresh⽅法(这个就是最核⼼的容器初始化⽅法)。
1、Resource定位:在refresh⽅法中调⽤obtainFreshBeanFactory⽅法告诉⼦类刷新beanfactory(其中是调⽤refreshBeanFactory刷新后getBeanFactory获取刷新后的factory返回)。
在刷新过程refreshBeanFactory中如果factory已经有了要消除再新建factory,其中loadBeanDefinitions是加载bean定义的⽅法。
在loadBeanDefinitions⽅法中创建了BeanDefinitionReader的实现类调⽤其loadBeanDefinitions⽅法(这个⽅法是重载⽅法,参数有为Resource的也有为String路径的,getConfigResources⽅法(默认返回null,⼦类重写,如ClassPathXmlApplicationContext类)和getConfigLocations⽅法获得Resource集合和资源路径集合(⼀般⼀个为空,⼀般是将容器的参数path设定为configLocations,ClassPathXmlApplicationContext有⼀种构造器是不设定configLocations⽽是直接⽤参数path⽣成ClassPathResource集合设定为configResources)分别进⾏load,实际上以路径为参数的重载⽅法在定位完Resource也会调⽤以resource为参数的loadBeanDefinitions来解析载⼊BeanDefinition,这个是第⼆步在下⾯介绍)。
完成端口详细解析

关于完成端口(IOCP)的文章汇总- [C/C++]版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明/logs/32007489.html首先讨论一下I/O Completion Ports试图解决什么样的问题。
写一个IO Intensive服务器程序,对每一个客户请求生成一个新的child process/worker thread来处理,每个process/thread使用同步IO,这是最经典古老的解法了。
在这之上的改进是prefork 多个process 或者使用线程池。
(使用process或thread,原理都差不多,thread的context switch花销要比process switch要小。
为了论述简单,下面只讨论线程。
)这种结构的并发性并不高,哪怕你用C++, C甚至汇编来写,效率都不会很高,究其原因,在于两点:一.同步IO,每个线程大多数时间在等IO request的结束。
IO相对于CPU,那是极极慢的。
我翻了翻手里的Computer Architecture, A Quantitative Approach第二版,1996年出的,里面对CPU Register, CPU Cache, RAM, Disk,列的access time如下:Java代码1.Registers: 2-5 nano seconds2.CPU Cache: 3-10 nano seconds3.RAM: 80-400 nano seconds4.Disk: 5000000 nano seconds (5 milli seconds)如今CPU又按照摩尔定律发展了十年后,这个硬盘还是机械式的磁头移来移去读写,尽管如今disk controller都有cache,也在发展,但和CPU相比,差距越来越大。
(谁有最新数据可以贴上来。
)二.生成数量大大超过CPU总数的线程。
这样做有两个弊端,第一是每个线程要占用内存,Windows底下每个thread自己stack的省缺大小为1M,32位程序下一个用户程序最大能利用的内存也就3G,生成3000个线程,内存就没了。
简述iocp模型的原理和工作过程

简述iocp模型的原理和工作过程IOCP(Input/Output Completion Port)模型是一种高效的异步IO 机制,它可以帮助我们更好地处理并发IO请求。
在本文中,我们将详细介绍IOCP模型的原理和工作过程。
一、IOCP模型的基本原理1.1 异步IO在传统的同步IO模型中,当程序调用一个IO操作时,它必须等待该操作完成后才能继续执行后面的代码。
这种方式会导致程序在等待IO 操作完成时出现阻塞,从而浪费了CPU资源。
相比之下,异步IO模型允许程序调用一个IO操作后立即返回,并在后台处理该操作。
当该操作完成时,系统将通知程序,并返回结果。
这种方式可以提高程序的并发性和吞吐量。
1.2 IOCP机制为了更好地支持异步IO,Windows引入了IOCP机制。
它是一种通知机制,可以帮助我们更好地处理异步IO请求。
具体来说,当一个异步IO请求被提交到系统中时,系统会为其分配一个I/O Completion Port(即完成端口)。
当该请求完成时,系统将通知该端口,并返回相关信息。
程序可以通过监听该端口来获取请求完成的通知,并进行相应的处理。
二、 IOCP模型的工作过程2.1 创建I/O Completion Port首先需要创建I/O Completion Port(以下简称IOCP)。
可以通过CreateIoCompletionPort函数来创建一个IOCP。
该函数返回一个句柄,该句柄用于后续的操作。
2.2 将Socket与IOCP关联接下来需要将Socket与IOCP关联。
可以通过CreateIoCompletionPort或者WSAEventSelect函数来实现。
2.3 提交异步IO请求当需要进行异步IO操作时,可以使用WSASend、WSARecv等函数来提交异步IO请求。
这些函数会将请求提交到系统中,并立即返回。
2.4 处理完成通知当一个异步IO请求完成时,系统会向其关联的IOCP发送一个完成通知。
IOCP_原理_代码

Windows I/O完成端口WINDOWS完成端口编程1、基本概念2、WINDOWS完成端口的特点3、完成端口(Completion Ports )相关数据结构和创建4、完成端口线程的工作原理5、Windows完成端口的实例代码WINDOWS完成端口编程摘要:开发网络程序从来都不是一件容易的事情,尽管只需要遵守很少的一些规则:创建socket,发起连接,接受连接,发送和接收数据,等等。
真正的困难在于:让你的程序可以适应从单单一个连接到几千个连接乃至于上万个连接。
利用Windows完成端口进行重叠I/O的技术,可以很方便地在Windows平台上开发出支持大量连接的网络服务程序。
本文介绍在Windows平台上使用完成端口模型开发的基本原理,同时给出实际的例子。
本文主要关注C/S结构的服务器端程序,因为一般来说,开发一个大容量、具有可扩展性的winsock程序就是指服务程序。
1、基本概念设备---指windows操作系统上允许通信的任何东西,比如文件、目录、串行口、并行口、邮件槽、命名管道、无名管道、套接字、控制台、逻辑磁盘、物理磁盘等。
绝大多数与设备打交道的函数都是CreateFile/ReadFile/WriteFile 等,所以我们不能看到**File函数就只想到文件设备。
与设备通信有两种方式,同步方式和异步方式:同步方式下,当调用ReadFile这类函数时,函数会等待系统执行完所要求的工作,然后才返回;异步方式下,ReadFile这类函数会直接返回,系统自己去完成对设备的操作,然后以某种方式通知完成操作。
重叠I/O----顾名思义,就是当你调用了某个函数(比如ReadFile)就立刻返回接着做自己的其他动作的时候,系统同时也在对I/0设备进行你所请求的操作,在这段时间内你的程序和系统的内部动作是重叠的,因此有更好的性能。
所以,重叠I/O是在异步方式下使用I/O设备的。
重叠I/O需要使用的一个非常重要的数据结构:OVERLAPPED。
IOCP详解

IOCP详解简介: IOCP(I/O Completion Port,I/O完成端⼝)是性能最好的⼀种I/O模型。
它是应⽤程序使⽤线程池处理异步I/O请求的⼀种机制。
IOCP详解IOCP(I/O Completion Port,I/O完成端⼝)是性能最好的⼀种I/O模型。
它是应⽤程序使⽤线程池处理异步I/O请求的⼀种机制。
在处理多个并发的异步I/O请求时,以往的模型都是在接收请求是创建⼀个线程来应答请求。
这样就有很多的线程并⾏地运⾏在系统中。
⽽这些线程都是可运⾏的,Windows内核花费⼤量的时间在进⾏线程的上下⽂切换,并没有多少时间花在线程运⾏上。
再加上创建新线程的开销⽐较⼤,所以造成了效率的低下。
Windows Sockets应⽤程序在调⽤WSARecv()函数后⽴即返回,线程继续运⾏。
当系统接收数据完成后,向完成端⼝发送通知包(这个过程对应⽤程序不可见)。
应⽤程序在发起接收数据操作后,在完成端⼝上等待操作结果。
当接收到I/O操作完成的通知后,应⽤程序对数据进⾏处理。
完成端⼝其实就是上⾯两项的联合使⽤基础上进⾏了⼀定的改进。
⼀个完成端⼝其实就是⼀个通知队列,由操作系统把已经完成的重叠I/O请求的通知放⼊其中。
当某项I/O操作⼀旦完成,某个可以对该操作结果进⾏处理的⼯作者线程就会收到⼀则通知。
⽽套接字在被创建后,可以在任何时候与某个完成端⼝进⾏关联。
众所皆知,完成端⼝是在WINDOWS平台下效率最⾼,扩展性最好的IO模型,特别针对于WINSOCK的海量连接时,更能显⽰出其威⼒。
其实建⽴⼀个完成端⼝的服务器也很简单,只要注意⼏个函数,了解⼀下关键的步骤也就⾏了。
分为以下⼏步来说明完成端⼝:0) 同步IO与异步IO1) 函数2) 常见问题以及解答3) 步骤4) 例程0、同步IO与异步IO同步I/O⾸先我们来看下同步I/O操作,同步I/O操作就是对于同⼀个I/O对象句柄在同⼀时刻只允许⼀个I/O操作,原理图如下:由图可知,内核开始处理I/O操作到结束的时间段是T2~T3,这个时间段中⽤户线程⼀直处于等待状态,如果这个时间段⽐较短,则不会有什么问题,但是如果时间⽐较长,那么这段时间线程会⼀直处于挂起状态,这就会很严重影响效率,所以我们可以考虑在这段时间做些事情。
iocp_1_实现步骤

IOCP 是什么以下就是IOCP的模型图,能看懂么?IOCP模型(图1.1)<一>IOCP实现步骤如果懂得了IOCP的工作原理,它实现起来是很简单的。
它的实现步骤如下:1.创建好IOCP2.创建Socket(socket可以是由Accept得到)3.将Socket关联到IOCP4.socket向IOCP提交各种所需请求5.IOCP操作完成之后将结果返回给socket6.重复步骤3和4 ,直到socket关闭它就那么几个步骤,但实现起来需要不少的代码。
以下就以创建一个客户端的socket为例,先做部分的讲解。
这里主要讲解原理,函数的参数和返回值先忽略。
1.//创建IOCP// 利用函数CreateIoCompletionPort 创建IOCP// 注意参数设置m_hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,(ULONG_PTR)0,0);// m_hIocp 就代表一个完成端口了2.// 创建连接型的Socket// 利用利用函数WSASocket创建socket,必须指定WSA_FLAG_OVERLAPPEDm_sockClient = ::WSASocket(AF_INET,SOCK_STREAM, IPPROTO_TCP, NULL, NULL, WSA_FLAG_OVERLAPPED);// m_sockClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // 这样也可以// 默认为WSA_FLAG_OVERLAPPED// 以下的绑定很重要,也是容易漏掉的。
(如果少了绑定,在ConnextEx 时将得到错误代码:10022—提供了一个无效的参数sockaddr_in local_addr;ZeroMemory(&local_addr, sizeof(sockaddr_in));local_addr.sin_family = AF_INET;i nt irt = ::bind(m_sockClient, (sockaddr*)(&local_addr), sizeof(sockaddr_in));// m_sockClient 是创建好的socket3.//将Socket关联到IOCP// 又利用上了CreateIoCompletionPort,它将socket关联到IOCPCreateIoCompletionPort((HANDLE)m_sockClient,m_hIocp,(ULONG_PTR)m_sockClient,0);// 已将sockClient关联到m_hIocp// (ULONG_PTR)m_sockClient 为以后识别是那个socket的操作4.// socket向IOCP提交各种所需请求, 这里提交的是连接请求// 代码比较长,将整个函数都拷贝了过来BOOL CIOCP_ClientDlg::ConnectToServer(){//----------------------LPFN_CONNECTEX m_lpfnConnectEx = NULL;DWORD dwBytes = 0;GUID GuidConnectEx = WSAID_CONNECTEX;// 重点,获得ConnectEx函数的指针if (SOCKET_ERROR == WSAIoctl(m_sockClient, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidConnectEx, sizeof (GuidConnectEx),&m_lpfnConnectEx, sizeof (m_lpfnConnectEx), &dwBytes, 0, 0)){TRACE( "WSAIoctl is failed. Error code = %d", WSAGetLastError());return FALSE;}MYOVERLAPPED *pmyoverlapped = new MYOVERLAPPED; // socket和I/O通讯的载体pmyoverlapped->operateType = OP_CONNECT; // 设置请求类型,得到I/O结果时根据此// //来识别请求类型pmyoverlapped->hEvent = NULL; // 非事件模型// 设置连接目标地址sockaddr_in addrPeer;ZeroMemory(&addrPeer, sizeof(sockaddr_in));addrPeer.sin_family = AF_INET;addrPeer.sin_addr.s_addr = inet_addr( "192.168.0.15" );addrPeer.sin_port = htons( 5400 );int nLen = sizeof(addrPeer);PVOID lpSendBuffer = NULL;DWORD dwSendDataLength = 0;DWORD dwBytesSent = 0;// 重点BOOL bResult = m_lpfnConnectEx(m_sockClient,(sockaddr*)&addrPeer, // [in] 对方地址nLen, // [in] 对方地址长度lpSendBuffer, // [in] 连接后要发送的内容,这里不用dwSendDataLength, // [in] 发送内容的字节数,这里不用&dwBytesSent, // [out] 发送了多少个字节,这里不用(OVERLAPPED*)pmyoverlapped); //[in] 这东西复杂,下一篇有详解if (!bResult ) // 返回值处理{if( WSAGetLastError() != ERROR_IO_PENDING) // 调用失败{TRACE(TEXT("ConnextEx error: %d\n"),WSAGetLastError());return FALSE;}else;//操作未决(正在进行中…){TRACE0("WSAGetLastError() == ERROR_IO_PENDING\n");// 操作正在进行中}}return TRUE;}// 在这个函数中重点是WSAIoctl函数(得到ConnectEx函数地址)和m_lpfnConnectEx 函数指针(进行ConnectEx调用,也就是向I/O提交连接对方的请求)。
ioc和aop的实现原理

ioc和aop的实现原理随着软件开发的不断发展,面向对象编程已经成为了主流。
在面向对象编程中,对象是程序的基本组成部分,而依赖注入(IOC)和面向切面编程(AOP)则成为了面向对象编程的两种重要技术。
本文将介绍IOC和AOP的实现原理,帮助读者更好地理解这两种技术。
一、什么是IOC依赖注入(IOC)是一种编程模式,它通过将对象的创建和依赖关系的管理交给容器来实现。
IOC的主要思想是将对象的创建和依赖关系的管理从代码中抽离出来,交给容器来管理,从而实现解耦。
在IOC模式中,容器是一个对象工厂,它负责创建和管理对象。
容器负责创建对象的实例,并将依赖关系注入到对象中。
通过IOC模式,我们可以将对象的创建和依赖关系的管理从代码中解耦出来,使得代码更加灵活和可维护。
二、IOC的实现原理IOC的实现原理主要是通过反射和配置文件来实现的。
1. 反射反射是Java语言的一种特性,它允许程序在运行时获取类的信息,创建对象,调用方法等。
在IOC中,反射被广泛应用,它可以帮助我们动态地创建对象,并将依赖关系注入到对象中。
例如,我们可以通过反射来创建一个类的实例,如下所示:Class clazz = Class.forName('er');User user = (User) clazz.newInstance();在上面的代码中,我们使用反射来获取User类的Class对象,然后通过newInstance()方法创建User类的实例。
2. 配置文件配置文件是IOC的另一个重要组成部分,它用于描述对象的创建和依赖关系。
配置文件通常是一个XML文件,其中包含了对象的类名、属性值和依赖关系等信息。
例如,下面是一个简单的配置文件:<?xml version='1.0' encoding='UTF-8'?><beans><bean id='userService' class='erService'> <property name='userDao' ref='userDao'/></bean><bean id='userDao' class='erDaoImpl'/></beans>在上面的配置文件中,我们定义了两个Bean:UserService和UserDao。
IOCP编程之基本原理

IOCP编程之基本原理在我的博客之前写了很多关于IOCP的“行云流水”似的看了让人发狂的文章,尤其是几篇关于IOCP加线程池文章,更是让一些功力不够深厚的初学IOCP者,有种吐血的感觉。
为了让大家能够立刻提升内力修为,并且迅速的掌握IOCP这个Windows平台上的乾坤大挪移心法,这次我决定给大家好好补补这个基础。
要想彻底征服IOCP,并应用好IOCP这个模型,首先就让我们穿越到遥远的计算机青铜器时代(以出现PC为标志),那时候普通的PC安装的还是DOS平台,微软公司主要靠这个操作系统在IT界的原始丛林中打拼,在DOS中编写程序,不得不与很多的硬件直接打交道,而最常操作的硬件无非是键盘、声显卡、硬盘等等,这些设备都有一个特点就是速度慢,当然是相对于PC平台核心CPU的速度而言,尤其是硬盘这个机械电子设备,其速度对于完全电子化得CPU来说简直是“相对静止”的设备。
很多时候CPU可以干完n件(n>1000)事情的时间中,这些硬件可能还没有完成一件事情,显然让CPU和这些硬件同步工作将是一种严重的浪费,并且也不太可能,此时,聪明的硬件设计师们发明了一种叫做中断的操作方式,用以匹配这种速度上的严重差异。
中断工作的基本原理就是,CPU首先设置一个类似回调函数的入口地址,其次CPU对某个硬件发出一个指令,此时CPU 就去干别的活计了,最后那个慢的象蜗牛一样的硬件执行完那个指令后,就通知CPU,让CPU暂时“中断”手头的工作,去调用那个“回调函数”。
至此一个完整的中断调用就结束了。
这个模型曾经解决了显卡与CPU不同步的问题,最重要的是解决了硬盘速度与CPU速度严重不匹配的问题,并因此还派生出了更有名的DMA(直接内存访问技术,主要是指慢速硬件可以读写原本只能由CPU直接读写的内存)硬盘IO方式。
(注意这里说的中断工作方式只是中断工作方式的一种,并不是全部,详细的中断原理请参阅其它专业文献。
)其实“中断”方式更像是一种管理模型,比如在一个公司中,如果要老板时时刻刻盯着员工作事情,那么除非是超人,否则无人能够胜任,同时对于老板这个稀缺资源来说也是一种极起严重的浪费。
IOCP编程之基本原理

IOCP编程之基本原理
IOCP的基本原理可以概括为以下几个步骤:
2.创建异步I/O操作请求:应用程序需要向操作系统提交异步I/O操
作请求。
这些请求可以是读取文件、发送网络数据等操作。
在提交请求时,应用程序需要指定一个回调函数,用于接收I/O操作完成的通知。
3.将I/O操作请求与IOCP关联:将提交的异步I/O操作请求与IOCP
对象进行关联。
这样,操作系统就知道在I/O操作完成时通知哪个IOCP
对象。
4.启动I/O操作:应用程序可以开始执行其他任务,而无需等待I/O
操作完成。
操作系统会在后台进行I/O操作,并且在操作完成时通知
IOCP对象。
6.处理I/O操作的完成结果:应用程序在获取到完成通知后,可以根
据具体的I/O操作类型,来获取相应的完成结果。
例如,对于网络操作,
可以获取到接收或发送的数据。
7. 释放资源:当应用程序不再需要一些IOCP对象时,可以通过调用CloseHandle函数来关闭IOCP对象,释放相关资源。
使用IOCP编程模型的好处是可以提高系统的并发能力和吞吐量。
相
比于传统的同步I/O模型,IOCP模型将I/O操作的处理交给操作系统内核,而应用程序可以继续执行其他任务,从而提高了程序的并发性能。
此外,IOCP还可以有效地管理多个I/O操作,减少线程的竞争和上下文切
换开销,提高系统的吞吐量。
总之,IOCP编程是一种高效的异步I/O编程模型,可以提高应用程序的性能和并发能力。
了解IOCP的基本原理对于理解和使用该编程模型是很重要的,可以帮助我们编写出高效的网络和文件I/O程序。
iocp 编程 -回复

iocp 编程-回复IOCP(Input/Output Completion Ports)编程是一种高效的服务器端编程模型,它利用操作系统级的异步I/O机制,能够实现高性能、高可扩展性和高并发的网络应用程序。
本文将逐步解释IOCP编程,包括其原理、特点、实现方式以及常见应用场景。
一、IOCP编程的原理IOCP编程基于操作系统提供的异步I/O机制,通过操作系统内核中的完成端口(completion port)来实现异步I/O操作的管理和处理。
操作系统将I/O请求和完成事件的管理和调度交给了完成端口,应用程序通过与完成端口进行通信来管理和处理I/O操作。
当应用程序需要进行I/O操作时,它可以向完成端口提交一个I/O请求。
完成端口会将这个请求发送给操作系统的驱动程序,并立即返回给应用程序,不会阻塞应用程序的继续执行。
当I/O操作完成时,操作系统会将完成事件通知完成端口,完成端口再将完成事件通知给应用程序进行处理。
应用程序可以通过从完成端口获取完成事件来获取已完成的I/O操作的结果,而无需进行轮询等待。
通过这种方式,IOCP编程能够高效地处理大量的并发I/O操作,提高服务器性能和可扩展性。
二、IOCP编程的特点1. 高性能:IOCP编程利用了操作系统提供的异步I/O机制,能够实现高效率的I/O操作处理。
相对于传统的同步I/O模型,它能够极大地提升服务器的性能。
2. 高可扩展性:IOCP编程通过使用完成端口进行异步I/O操作的管理和处理,能够很好地适应大量并发连接的场景。
它能够实现更高的并发能力和更低的系统资源开销,使得服务器能够轻松应对高并发请求。
3. 简化了编程模型:相对于传统的多线程或多进程方式处理并发I/O操作的编程模型,IOCP编程可以减少线程和进程的创建和维护的开销,简化了编程模型。
应用程序只需要关注I/O操作提交和完成事件的处理,而不需要关心具体的线程或进程创建和管理。
三、IOCP编程的实现方式IOCP编程可以在不同的操作系统平台上实现,如Windows和Linux。
iocp例子

iocp例子IOCP(Input/Output Completion Port)是Windows平台上实现高性能异步I/O的机制。
下面是一个简单的IOCP示例,演示了如何使用IOCP实现异步socket通信:```c#include <winsock2.h>#include <windows.h>#include <stdio.h>#define MAX_CLIENTS 10#define PORT 12345typedef struct {OVERLAPPED overlapped;SOCKET socket;char buffer[1024];WSABUF wsaBuf;} PER_IO_DATA;int main() {// 初始化WinsockWSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {printf("Failed to initialize Winsock\n");return 1;}// 创建IOCPHANDLE hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);if (hIOCP == NULL) {printf("Failed to create IOCP\n");return 1;}// 创建监听socketSOCKET listenSocket = socket(AF_INET, SOCK_STREAM, 0);if (listenSocket == INVALID_SOCKET) {printf("Failed to create listen socket\n");return 1;}// 绑定端口SOCKADDR_IN serverAddr;serverAddr.sin_family = AF_INET;serverAddr.sin_port = htons(PORT);serverAddr.sin_addr.s_addr = INADDR_ANY;if (bind(listenSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) { printf("Bind failed\n");return 1;}// 将监听socket关联到IOCPif (CreateIoCompletionPort((HANDLE)listenSocket, hIOCP, (ULONG_PTR)listenSocket, 0) == NULL) {printf("Failed to associate listen socket with IOCP\n");return 1;}// 开始监听if (listen(listenSocket, SOMAXCONN) == SOCKET_ERROR) {printf("Listen failed\n");return 1;}printf("Server listening on port %d...\n", PORT);while (1) {// 接收连接SOCKADDR_IN clientAddr;int addrLen = sizeof(clientAddr);SOCKET clientSocket = accept(listenSocket, (SOCKADDR*)&clientAddr, &addrLen);if (clientSocket == INVALID_SOCKET) {printf("Accept failed\n");continue;}printf("Client connected: %s\n", inet_ntoa(clientAddr.sin_addr));// 将新连接socket关联到IOCPif (CreateIoCompletionPort((HANDLE)clientSocket, hIOCP, (ULONG_PTR)clientSocket, 0) == NULL) {printf("Failed to associate client socket with IOCP\n");closesocket(clientSocket);continue;}// 创建并初始化IO数据结构PER_IO_DATA* perIoData = (PER_IO_DATA*)malloc(sizeof(PER_IO_DATA));memset(perIoData, 0, sizeof(PER_IO_DATA));perIoData->socket = clientSocket;perIoData->wsaBuf.buf = perIoData->buffer;perIoData->wsaBuf.len = sizeof(perIoData->buffer);// 开始异步接收数据DWORD bytesReceived;DWORD flags = 0;if (WSARecv(clientSocket, &perIoData->wsaBuf, 1, &bytesReceived, &flags, &perIoData->overlapped, NULL) == SOCKET_ERROR) {if (WSAGetLastError() != WSA_IO_PENDING) {printf("Failed to start async receive\n");closesocket(clientSocket);free(perIoData);continue;}}}// 清理资源closesocket(listenSocket);CloseHandle(hIOCP);WSACleanup();return 0;}```这是一个简单的异步TCP服务器,使用IOCP处理连接和接收数据。
分享我写的IOCP:源码+思路

分享我写的IOCP:源码+思路⾸先说明,下⾯的代码仅是⼀个IOCP的demo,很多地⽅的设计⾮常差,当然也有⼀些设计还算可以:)。
此篇仅供对IOCP有些了解但⼜不深⼊的、需要⼀个稍微完整⽰例的、对⽹络编程感兴趣的同学参考。
点击这⾥整个程序的流程如下:流程完全是⽆阻塞的,主线程⾥,将收到的消息全都⼀次性取出后,然后派发。
所有欲发送的消息都缓存起来,等到更新的时候⼀起发送。
有些地⽅代码没有完善,⽐如断开连接后,socket、内存等资源的关闭回收。
要注意MAXRECEIVEDBUFFLENGTH这个宏,它是定义每个socket消息收发时缓冲区的⼤⼩。
如果很⼤,会⾮常吃内存的。
我在这⾥也没有做粘包、分包的情况处理。
⼯程还带了⼀个C#写的测试客户端。
在我的机器上,能有12W的连接。
关键代码如下:void MyIOCP::Execute(){PerHandleData* pPerHandleData = nullptr;PerIOData* pPerIOData = nullptr;LPOVERLAPPED lpOverLapped = nullptr;DWORD byteTransferred;BOOL bRet = FALSE;while (true){bRet = GetQueuedCompletionStatus(mCompletionPort,&byteTransferred,(PULONG_PTR)&pPerHandleData,/*(LPOVERLAPPED*)&pPerIOData*/&lpOverLapped,INFINITE);pPerIOData = (PerIOData*)CONTAINING_RECORD(lpOverLapped, PerIOData, overlapped);if (bRet == FALSE){if (pPerIOData == nullptr){// 退出线程。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Windows I/O完成端口2009-10-30 10:51WINDOWS完成端口编程1、基本概念2、WINDOWS完成端口的特点3、完成端口(Completion Ports )相关数据结构和创建4、完成端口线程的工作原理5、Windows完成端口的实例代码WINDOWS完成端口编程摘要:开发网络程序从来都不是一件容易的事情,尽管只需要遵守很少的一些规则:创建socket,发起连接,接受连接,发送和接收数据,等等。
真正的困难在于:让你的程序可以适应从单单一个连接到几千个连接乃至于上万个连接。
利用Windows完成端口进行重叠I/O的技术,可以很方便地在Windows平台上开发出支持大量连接的网络服务程序。
本文介绍在Windows平台上使用完成端口模型开发的基本原理,同时给出实际的例子。
本文主要关注C/S结构的服务器端程序,因为一般来说,开发一个大容量、具有可扩展性的winsock程序就是指服务程序。
1、基本概念设备---指windows操作系统上允许通信的任何东西,比如文件、目录、串行口、并行口、邮件槽、命名管道、无名管道、套接字、控制台、逻辑磁盘、物理磁盘等。
绝大多数与设备打交道的函数都是CreateFile/ReadFile/WriteFile 等,所以我们不能看到**File函数就只想到文件设备。
与设备通信有两种方式,同步方式和异步方式:同步方式下,当调用ReadFile这类函数时,函数会等待系统执行完所要求的工作,然后才返回;异步方式下,ReadFile这类函数会直接返回,系统自己去完成对设备的操作,然后以某种方式通知完成操作。
重叠I/O----顾名思义,就是当你调用了某个函数(比如ReadFile)就立刻返回接着做自己的其他动作的时候,系统同时也在对I/0设备进行你所请求的操作,在这段时间内你的程序和系统的内部动作是重叠的,因此有更好的性能。
所以,重叠I/O是在异步方式下使用I/O设备的。
重叠I/O需要使用的一个非常重要的数据结构:OVERLAPPED。
2、WINDOWS完成端口的特点Win32重叠I/O(Overlapped I/O)机制允许发起一个操作,并在操作完成之后接收信息。
对于那种需要很长时间才能完成的操作来说,重叠IO机制尤其有用,因为发起重叠操作的线程在重叠请求发出后就可以自由地做别的事情了。
在WinNT和Win2000上,提供的真正可扩展的I/O模型就是使用完成端口(Completion Port)的重叠I/O。
完成端口---是一种WINDOWS内核对象。
完成端口用于异步方式的重叠I/0情况下,当然重叠I/O不一定非得使用完成端口不可,同样设备内核对象、事件对象、告警I/0等也可使用。
但是完成端口内部提供了线程池的管理,可以避免反复创建线程的开销,同时可以根据CPU的个数灵活地决定线程个数,而且可以减少线程调度的次数从而提高性能。
其实类似于WSAAsyncSelect和select函数的机制更容易兼容Unix,但是难以实现我们想要的“扩展性”。
而且windows完成端口机制在操作系统的内部已经作了优化,从而具备了更高的效率。
所以,我们选择完成端口开始我们的服务器程序开发。
1)发起操作不一定完成:系统会在完成的时候通知你,通过用户在完成端口上的等待,处理操作的结果。
所以要有检查完成端口和取操作结果的线程。
在完成端口上守候的线程系统有优化,除非在执行的线程发生阻塞,不会有新的线程被激活,以此来减少线程切换造成的性能代价。
所以如果程序中没有太多的阻塞操作,就没有必要启动太多的线程,使用CPU数量的两倍,一般这么多线程就够了。
2)操作与相关数据的绑定方式:在提交数据的时候用户对数据打上相应的标记,记录操作的类型,在用户处理操作结果的时候,通过检查自己打的标记和系统的操作结果进行相应的处理。
3)操作返回的方式:一般操作完成后要通知程序进行后续处理。
但写操作可以不通知用户,此时如果用户写操作不能马上完成,写操作的相关数据会被暂存到非交换缓冲区中,在操作完成的时候,系统会自动释放缓冲区,此时发起完写操作,使用的内存就可以释放了。
但如果占用非交换缓冲太多会使系统停止响应。
3、完成端口(Completion Ports )相关数据结构和创建其实可以把完成端口看成系统维护的一个队列,操作系统把重叠IO操作完成的事件通知放到该队列里,由于是暴露“操作完成”的事件通知,所以命名为“完成端口”(Completion Ports)。
一个socket被创建后,就可以在任何时刻和一个完成端口联系起来。
OVERLAPPED数据结构typedef struct _OVERLAPPED {ULONG_PTR Internal; //被系统内部赋值,用来表示系统状态ULONG_PTR InternalHigh; //被系统内部赋值,表示传输的字节数union {struct {DWORD Offset; //与OffsetHigh合成一个64位的整数,用来表示从文件头部的多少字节开始操作DWORD OffsetHigh; //如果不是对文件I/O来操作,则Offset必须设定为0};PVOID Pointer;};HANDLE hEvent; //如果不使用,就务必设为0;否则请赋一个有效的Event 句柄} OVERLAPPED, *LPOVERLAPPED;下面是异步方式使用ReadFile的一个例子OVERLAPPED Overlapped;Overlapped.Offset=345;Overlapped.OffsetHigh=0;Overlapped.hEvent=0;//假定其他参数都已经被初始化ReadFile(hFile,buffer,sizeof(buffer),&dwNumBytesRead,&Overlapped); 这样就完成了异步方式读文件的操作,然后ReadFile函数返回,由操作系统做自己的事情。
下面介绍几个与OVERLAPPED结构相关的函数。
等待重叠I/0操作完成的函数BOOL GetOverlappedResult (HANDLE hFile,LPOVERLAPPED lpOverlapped, //接受返回的重叠I/0结构LPDWORD lpcbTransfer, //成功传输了多少字节数BOOL fWait //TRUE只有当操作完成才返回,FALSE直接返回,如果操作没有完成,//通过用GetLastError( )函数会返回ERROR_IO_INCOMPLETE);而宏HasOverlappedIoCompleted可以帮助我们测试重叠I/0操作是否完成,该宏对OVERLAPPED结构的Internal成员进行了测试,查看是否等于STATUS_PENDING值。
一般来说,一个应用程序可以创建多个工作线程来处理完成端口上的通知事件。
工作线程的数量依赖于程序的具体需要。
但是在理想的情况下,应该对应一个CPU 创建一个线程。
因为在完成端口理想模型中,每个线程都可以从系统获得一个“原子”性的时间片,轮番运行并检查完成端口,线程的切换是额外的开销。
但在实际开发的时候,还要考虑这些线程是否牵涉到其他堵塞操作的情况。
如果某线程进行堵塞操作,系统则将其挂起,让别的线程获得运行时间。
因此,如果有这样的情况,可以多创建几个线程来尽量利用时间。
创建完成端口的函数完成端口是一个内核对象,使用时它总是要和至少一个有效的设备句柄相关联,完成端口是一个复杂的内核对象,创建它的函数是:HANDLE CreateIoCompletionPort(IN HANDLE FileHandle,IN HANDLE ExistingCompletionPort,IN ULONG_PTR CompletionKey,IN DWORD NumberOfConcurrentThreads);通常创建工作分两步:第一步,创建一个新的完成端口内核对象,可以使用下面的函数:HANDLE CreateNewCompletionPort(DWORD dwNumberOfThreads){returnCreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,NULL,dwNumberOfThrea ds);};第二步,将刚创建的完成端口和一个有效的设备句柄关联起来,可以使用下面的函数:bool AssicoateDeviceWithCompletionPort(HANDLE hCompPort,HANDLE hDevice,DWORD dwCompKey){HANDLEh=CreateIoCompletionPort(hDevice,hCompPort,dwCompKey,0);return h==hCompPort;};说明如下:1)CreateIoCompletionPort函数也可以一次性的既创建完成端口对象,又关联到一个有效的设备句柄。
2)CompletionKey是一个可以自己定义的参数,我们可以把一个结构的地址赋给它,然后在合适的时候取出来使用,最好要保证结构里面的内存不是分配在栈上,除非你有十分的把握内存会保留到你要使用的那一刻。
3)NumberOfConcurrentThreads用来指定要允许同时运行的的线程的最大个数,通常我们指定为0,这样系统会根据CPU的个数来自动确定。
4)创建和关联的动作完成后,系统会将完成端口关联的设备句柄、完成键作为一条纪录加入到这个完成端口的设备列表中。
如果你有多个完成端口,就会有多个对应的设备列表。
如果设备句柄被关闭,则表中该纪录会被自动删除。
4、完成端口线程的工作原理1)完成端口管理线程池完成端口可以帮助我们管理线程池,但是线程池中的线程需要我们自己使用_beginthreadex来创建,凭什么通知完成端口管理我们的新线程呢?答案在函数GetQueuedCompletionStatus。
该函数原型:BOOL GetQueuedCompletionStatus(IN HANDLE CompletionPort,OUT LPDWORD lpNumberOfBytesTransferred,OUT PULONG_PTR lpCompletionKey,OUT LPOVERLAPPED *lpOverlapped,IN DWORD dwMilliseconds);这个函数试图从指定的完成端口的I/0完成队列中提取纪录。
只有当重叠I/O 动作完成的时候,完成队列中才有纪录。
凡是调用这个函数的线程将会被放入到完成端口的等待线程队列中,因此完成端口就可以在自己的线程池中帮助我们维护这个线程。