完成端口加线程池技术实现

合集下载

线程池的原理与实现详解

线程池的原理与实现详解

线程池的原理与实现详解/article/41375.htm2013下面利用C 语言来实现一个简单的线程池,为了使得这个线程池库使用起来更加方便,特在C实现中加入了一些OO的思想,与Objective-C不同,它仅仅是使用了struct来模拟了c++中的类,其实这种方式在linux内核中大量可见一. 线程池的简介通常我们使用多线程的方式是,需要时创建一个新的线程,在这个线程里执行特定的任务,然后在任务完成后退出。

这在一般的应用里已经能够满足我们应用的需求,毕竟我们并不是什么时候都需要创建大量的线程,并在它们执行一个简单的任务后销毁。

但是在一些web、email、database等应用里,比如彩铃,我们的应用在任何时候都要准备应对数目巨大的连接请求,同时,这些请求所要完成的任务却又可能非常的简单,即只占用很少的处理时间。

这时,我们的应用有可能处于不停的创建线程并销毁线程的状态。

虽说比起进程的创建,线程的创建时间已经大大缩短,但是如果需要频繁的创建线程,并且每个线程所占用的处理时间又非常简短,则线程创建和销毁带给处理器的额外负担也是很可观的。

线程池的作用正是在这种情况下有效的降低频繁创建销毁线程所带来的额外开销。

一般来说,线程池都是采用预创建的技术,在应用启动之初便预先创建一定数目的线程。

应用在运行的过程中,需要时可以从这些线程所组成的线程池里申请分配一个空闲的线程,来执行一定的任务,任务完成后,并不是将线程销毁,而是将它返还给线程池,由线程池自行管理。

如果线程池中预先分配的线程已经全部分配完毕,但此时又有新的任务请求,则线程池会动态的创建新的线程去适应这个请求。

当然,有可能,某些时段应用并不需要执行很多的任务,导致了线程池中的线程大多处于空闲的状态,为了节省系统资源,线程池就需要动态的销毁其中的一部分空闲线程。

因此,线程池都需要一个管理者,按照一定的要求去动态的维护其中线程的数目。

基于上面的技术,线程池将频繁创建和销毁线程所带来的开销分摊到了每个具体执行的任务上,执行的次数越多,则分摊到每个任务上的开销就越小。

完成端口讲解

完成端口讲解

完成端口一、什么是完成端口从本质上讲,完成端口是一种异步I/O技术,它提供一个内核对象,可以关联多个I/O设备,同时关联一个线程池,线程池中的线程通常处于睡眠状态,当有I/O出现时,完成端口唤醒等待线程队列中的线程进行处理。

完成端口有着良好的伸缩性灵活性以及较高的效率,一般用来创建大型的服务器。

我们知道,一个服务器应用程序结构可以分为串行模式和并发模式。

在串行模式中,一次只能处理一个请求,第二个请求必须等待第一个请求被处理完毕才能开始处理,适合于客户量比较小的情况;在并发模式中,针对每个请求创建一个线程,使得多个请求可以同时得到处理,因而提高了程序的性能。

但是,我们再进一步思考,如果有多个设备同时发出IO请求,那么在并发模式中也必须创建与之相同个数的线程,但是,CPU的个数是有限的,多于CPU个数的可运行线程就没有意义了,系统不得不在多个线程间进行上下文切换,以使得多个线程并发执行,这必然浪费宝贵的CPU周期。

另外,虽然创建线程较进程而言开销要小,但也并不意味着没有开销,尤其当数量比较大的时候。

在完成端口模型中,引入了线程池的概念,在应用程序初始化时创建一个线程池,在没有请求时处于等待状态,当请求完成时唤醒一个线程运行,运行完毕后重新放入线程池中,等待其他请求使用。

由于不必为每个请求创建一个线程,从而减少了线程的数量,省去了运行中途创建线程的开销,进一步提高了程序的性能。

二、完成端口的内部结构由于完成端口也是一个内核对象,故我们看一下它的内部结构。

完成端口对象包含五个不同的数据结构:1、设备列表:表相:设备句柄、完成键。

当调用CreateIoCompletionPort时将设备与完成端口关联起来,同时在该数据结构中创建一项。

每当向完成端口关联一个设备时,系统向该完成端口的设备列表中加入一条信息。

2、/index.php/Main_Page-->: 150%; mso-bidi-font-size: 10.5pt">I/O完成队列:表相:传输的字节数、32位完成键、I/O请求的OVERLAPPED结构指针、错误代码当一个设备的异步I/O请求完成时,系统检测该设备是否关联了一个完成端口,如果是,系统就向该完成端口的I/O完成队列中加入完成的I/O请求项。

linux线程池实现原理

linux线程池实现原理

linux线程池实现原理
Linux线程池的实现原理是通过一个任务队列和一组线程来实
现的。

线程池会预先创建一定数量的线程,并将这些线程放入一个线程池中。

当有新的任务需要执行时,将任务添加到任务队列中。

线程池中的线程会循环地从任务队列中取出任务并执行。

当某个线程取出任务后,会执行任务的具体逻辑。

任务执行完毕后,线程会再次从任务队列中取出下一个任务并执行。

当线程池中的线程执行完任务后,并不会立即结束线程,而是会继续从任务队列中取出任务。

这样可以减少线程的创建和销毁的开销,并能提高任务的执行效率。

线程池还可以设置最大线程数和最小线程数,以控制线程池中线程的数量。

当任务队列中的任务较多时,线程池会创建新的线程来处理任务。

当任务队列中的任务较少时,线程池会销毁多余的线程,以节省系统资源。

通过使用线程池,可以提高系统的并发性能,减少线程的创建和销毁开销,并能更好地控制系统资源的使用率。

同时,线程池还可以根据任务的类型和优先级来调整线程的执行顺序,以实现不同的调度策略。

异步io、apc、io完成端口、线程池与高性能服务器

异步io、apc、io完成端口、线程池与高性能服务器

异步IO、APC、IO完成端口、线程池与高性能服务器背景:轮询PIO DMA 中断早期IO设备的速度与CPU相比,还不是太悬殊。

CPU定时轮询一遍IO设备,看看有无处理要求,有则加以处理,完成后返回继续工作。

至今,软盘驱动器还保留着这种轮询工作方式。

随着CPU性能的迅速提高,这种效率低下的工作方式浪费了大量的CPU时间。

因此,中断工作方式开始成为普遍采用的技术。

这种技术使得IO设备在需要得到服务时,能够产生一个硬件中断,迫使CPU放弃目前的处理任务,进入特定的中断服务过程,中断服务完成后,再继续原先的处理。

这样一来,IO设备和CPU可以同时进行处理,从而避免了CPU等待IO完成。

早期数据的传输方式主要是PIO(程控IO)方式。

通过对IO地址编程方式的方式来传输数据。

比如串行口,软件每次往串行口上写一个字节数据,串口设备完成传输任务后,将会产生一个中断,然后软件再次重复直到全部数据发送完成。

性能更好的硬件设备提供一个FIFO(先进先出缓冲部件),可以让软件一次传输更多的字节。

显然,使用PIO方式对于高速IO设备来说,还是占用了太多的CPU时间(因为需要通过CPU编程控制传输)。

而DMA(直接内存访问)方式能够极大地减少CPU处理时间。

CPU仅需告诉DMA控制器数据块的起始地址和大小,以后DMA控制器就可以自行在内存和设备之间传输数据,其间CPU可以处理其他任务。

数据传输完毕后将会产生一个中断。

同步文件IO和异步文件IO下面摘抄于MSDN《synchronous file I/O and asynchronous file I/O》。

有两种类型的文件IO同步:同步文件IO和异步文件IO。

异步文件IO也就是重叠IO。

在同步文件IO中,线程启动一个IO操作然后就立即进入等待状态,直到IO操作完成后才醒来继续执行。

而异步文件IO方式中,线程发送一个IO请求到内核,然后继续处理其他的事情,内核完成IO请求后,将会通知线程IO 操作完成了。

完成端口

完成端口

Windows socket之IO完成端口(IOCP)模型开发IO完成端口是一种内核对象。

利用完成端口,套接字应用程序能够管理数百上千个套接字。

应用程序创建完成端口对象后,通过指定一定数量的服务线程,为已经完成的重叠IO操作提供服务。

该模型可以达到最后的系统性能。

完成端口是一种真正意义上的异步模型。

在重叠IO模型中,当Windows socket应用程序在调用WSARecv函数后立即返回,线程继续运行。

另一线程在在完成端口等待操作结果,当系统接收数据完成后,会向完成端口发送通知,然后应用程序对数据进行处理。

为了将Windows打造成一个出色的服务器环境,Microsoft开发出了IO完成端口。

它需要与线程池配合使用。

服务器有两种线程模型:串行和并发模型。

串行模型:单个线程等待客户端请求。

当请求到来时,该线程被唤醒来处理请求。

但是当多个客户端同时向服务器发出请求时,这些请求必须依次被请求。

并发模型:单个线程等待请求到来。

当请求到来时,会创建新线程来处理。

但是随着更多的请求到来必须创建更多的线程。

这会导致系统内核进行上下文切换花费更多的时间。

线程无法即时响应客户请求。

伴随着不断有客户端请求、退出,系统会不断新建和销毁线程,这同样会增加系统开销。

而IO完成端口却可以很好的解决以上问题。

它的目标就是实现高效服务器程序。

与重叠IO相比较重叠IO与IO完成端口模型都是异步模型。

都可以改善程序性能。

但是它们也有以下区别:1:在重叠IO使用事件通知时,WSAWaitForMultipleEvents 只能等待WSA_MAXIMUM_WAIT_EVENTS(64)个事件。

这限制了服务器提供服务的客户端的数量。

2:事件对象、套接字和WSAOVERLAPPED结构必须一一对应关系,如果出现一点疏漏将会导致严重的后果。

完成端口模型实现包括以下步骤:1:创建完成端口2:将套接字与完成端口关联。

3:调用输入输出函数,发起重叠IO操作。

线程池调用接口的例子

线程池调用接口的例子

线程池调用接口的例子线程池是一种用于管理线程的机制,可以有效地提高程序的性能和响应速度。

下面是一个使用线程池调用接口的简单示例。

首先,我们需要创建一个线程池。

在Java中,我们可以使用java.util.concurrent.ExecutorService类来创建线程池。

例如,我们可以创建一个固定大小的线程池:javaExecutorService executor = Executors.newFixedThreadPool(10);上面的代码创建了一个包含10个线程的线程池。

接下来,我们可以使用线程池来执行任务。

任务可以是一个函数或者一个方法,例如:javapublic void doTask(String param) {// 执行任务的代码}然后,我们可以使用线程池来调用这个方法:javaexecutor.submit(() -> doTask("Hello, world!"));上面的代码将任务提交给线程池,并立即返回。

线程池将在一个可用的线程上执行这个任务。

如果我们需要执行多个任务,我们可以使用循环来提交它们:javafor (int i = 0; i < 10; i++) {executor.submit(() -> doTask("Task " + i));}上面的代码将提交10个任务给线程池,每个任务都调用doTask方法并传递一个不同的参数。

当我们不再需要使用线程池时,我们应该关闭它以释放资源:javaexecutor.shutdown();上面的代码将关闭线程池。

在此之后,我们不能再提交新的任务,但可以等待已提交的任务完成。

C++线程池实现

C++线程池实现

C++ 线程池实现使用多线程编程可以显著提高程序的运行速度,由于现在的操作系统都是多核的,所以一个多线程的程序,由于系统内核是基于时间片轮询的,所以多线程程序再用系统内核的时间大大增多,所完成的任务就更快。

线程池头文件://---------------------------------------------------------------------------#ifndef CworkQueueH#define CworkQueueH//---------------------------------------------------------------------------#include <queue>#include<vcl.h>class CWorkQueue;/**用法原理:通过派生类WorkItemBase的dowork方法来实现,线程处理任务通过create任务创建线程,并且这些线程一直在for循环里等待事件监听一旦任务栈里有数据了触发线程执行任务。

**//*------------------------------------------------------------------------WorkItemBasethis is the basic WorkItem that the Work Queue Use its interface This class should be inherited and these virtual abstract functions implemented.DoWork()virtual abstract function is the function that is called when thework item turn has came to be poped out of the queue and be processed.Abort ()This function is called, when the Destroy function is called, for each of the WorkItemsThat are left in the queue.------------------------------------------------------------------------*/class WorkItemBase{virtual void DoWork(void* pThreadContext) = 0;virtual void Abort () = 0;friend CWorkQueue;};typedef std::queue<WorkItemBase*> WorkItemQueue,*PWorkItemQueue;/*------------------------------------------------------------------------CWorkQueueThis is the WorkOueue class also known as thread pool,the basic idea of this class is creating thread that are waiting on a queueof work item when the queue is inserted with items the threads wake up andperform the requered work and go to sleep again.------------------------------------------------------------------------*/class CWorkQueue{public:virtual~CWorkQueue(){};bool Create(const unsigned int nNumberOfThreads,void* *pThreadDataArray = NULL);bool InsertWorkItem(WorkItemBase* pWorkItem);void Destroy(int iWairSecond);int GetThreadTotalNum();private:static unsigned long__stdcall ThreadFunc( void* pParam ); WorkItemBase* RemoveWorkItem();int GetWorekQueueSize();enum{ABORT_EVENT_INDEX = 0,SEMAPHORE_INDEX,NUMBER_OF_SYNC_OBJ,};//申请到的线程PHANDLE m_phThreads;unsigned int m_nNumberOfThreads;void* m_pThreadDataArray;HANDLE m_phSincObjectsArray[NUMBER_OF_SYNC_OBJ]; CRITICAL_SECTION m_CriticalSection;PWorkItemQueue m_pWorkItemQueue;};#endifCPP实现#pragma hdrstop#include "CworkQueue.h"//---------------------------------------------------------------------------#include <assert.h>typedef struct_THREAD_CONTEXT{CWorkQueue* pWorkQueue;void* pThreadData;} THREAD_CONTEXT,*PTHREAD_CONTEXT;/*------------------------------------------------------------------------建立多线程 nNumberOfThreads多线程数目 ThreadData线程函数执行的参数------------------------------------------------------------------------*/bool CWorkQueue::Create(const unsigned int nNumberOfThreads,void* *ThreadData /*=NULL*/){//创建任务队列,存放后续将要执行的任务m_pWorkItemQueue = new WorkItemQueue();if(NULL == m_pWorkItemQueue ){return false;}//m_phSincObjectsArray保存了线程池的信号量和事件//m_phSincObjectsArray[ABORT_EVENT_INDEX]保存的是事件,当用户设置退出事件时使用//m_phSincObjectsArray[SEMAPHORE_INDEX]保存信号量,当用户设置执行任务时使用//创建信号量(多线程同步使用)/*在信号量上我们定义两种操作: Wait(等待)和 Release(释放)。

IOCP完成端口原理-详解

IOCP完成端口原理-详解

本文主要探讨一下windows平台上的完成端口开发及其与之相关的几个重要的技术概念,这些概念都是与基于IOCP的开发密切相关的,对开发人员来讲,又不得不给予足够重视的几个概念:1) 基于IOCP实现的服务吞吐量2)IOCP模式下的线程切换3)基于IOCP实现的消息的乱序问题。

一、IOCP简介提到IOCP,大家都非常熟悉,其基本的编程模式,我就不在这里展开了。

在这里我主要是把IOCP中所提及的概念做一个基本性的总结。

IOCP的基本架构图如下:如图所示:在IOCP中,主要有以下的参与者:--》完成端口:是一个FIFO队列,操作系统的IO子系统在IO操作完成后,会把相应的IO packet放入该队列。

--》等待者线程队列:通过调用GetQueuedCompletionStatus API,在完成端口上等待取下一个IO packet。

--》执行者线程组:已经从完成端口上获得IO packet,在占用CPU进行处理。

除了以上三种类型的参与者。

我们还应该注意两个关联关系,即:--》IO Handle与完成端口相关联:任何期望使用IOCP的方式来处理IO请求的,必须将相应的IO Handle与该完成端口相关联。

需要指出的时,这里的IO Handle,可以是File的Handle,或者是Socket的Handle。

--》线程与完成端口相关联:任何调用GetQueuedCompletionStatus API的线程,都将与该完成端口相关联。

在任何给定的时候,该线程只能与一个完成端口相关联,与最后一次调用的GetQueuedCompletionStatus为准。

二、高并发的服务器(基于socket)实现方法一般来讲,实现基于socket的服务器,有三种实现的方式(thread per request的方式,我就不提了:)):第一、线程池的方式。

使用线程池来对客户端请求进行服务。

使用这种方式时,当客户端对服务器的连接是短连接(所谓的短连接,即:客户端对服务器不是长时间连接)时,是可以考虑的。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

WinSock 异步I/O模型[5]---完成端口 - Completion Port----------------------------------------------------------------------------如果你想在Windows平台上构建服务器应用,那么I/O模型是你必须考虑的。

Windows操作系统提供了五种I/O模型,分别是:■选择(select);■异步选择(WSAAsyncSelect);■事件选择(WSAEventSelect);■重叠I/O(Overlapped I/O);■完成端口(Completion Port) 。

每一种模型适用于一种特定的应用场景。

程序员应该对自己的应用需求非常明确,综合考虑到程序的扩展性和可移植性等因素,作出自己的选择。

==============================================█“完成端口”模型是迄今为止最复杂的一种 I/O 模型。

但是,若一个应用程序同时需要管理很多的套接字,那么采用这种模型,往往可以达到最佳的系统性能!但缺点是,该模型只适用于Windows NT 和 Windows 2000 以上版本的操作系统。

█因其设计的复杂性,只有在你的应用程序需要同时管理数百乃至上千个套接字的时候,而且希望随着系统内安装的CPU数量的增多,应用程序的性能也可以线性提升,才应考虑采用“完成端口”模型。

█从本质上说,完成端口模型要求我们创建一个 Win32 完成端口对象,通过指定数量的线程,对重叠 I/O 请求进行管理,以便为已经完成的重叠 I/O 请求提供服务。

█※※※大家可以这样理解,一个完成端口其实就是一个完成 I/O 的通知队列,由操作系统把已经完成的重叠 I/O 请求的通知放入这个队列中。

当某项 I/O 操作一旦完成,某个可以对该操作结果进行处理的工作者线程就会收到一则通知,工作者线程再去做一些其他的善后工作,比如:将收到的数据进行显示,等等。

而套接字在被创建后,可以在任何时候与某个完成端口进行关联。

※※※通常情况下,我们会在应用程序中创建一定数量的工作者线程来处理这些通知。

线程数量取决于应用程序的特定需要。

理想的情况是,线程数量等于处理器的数量,不过这也要求任何线程都不应该执行诸如同步读写、等待事件通知等阻塞型的操作,以免线程阻塞。

每个线程都将分到一定的CPU时间,在此期间该线程可以运行,然后另一个线程将分到一个时间片并开始执行。

如果某个线程执行了阻塞型的操作,操作系统将剥夺其未使用的剩余时间片并让其它线程开始执行。

也就是说,前一个线程没有充分使用其时间片,当发生这样的情况时,应用程序应该准备其它线程来充分利用这些时间片。

█使用这种模型之前,首先要创建一个 I/O 完成端口对象,用它面向任意数量的套接字句柄,管理多个 I/O 请求。

要做到这一点,需要调用 CreateCompletionPort 函数,其定义如下:HANDLE WINAPI CreateIoCompletionPort(__in HANDLE FileHandle,__in HANDLE ExistingCompletionPort,__in ULONG_PTR CompletionKey,__in DWORD NumberOfConcurrentThreads);要注意该函数有两个功能:●用于创建一个完成端口对象;●将一个句柄同完成端口对象关联到一起。

如果仅仅为了创建一个完成端口对象,唯一注意的参数便是NumberOfConcurrentThreads(并发线程的数量),前面三个参数可忽略。

NumberOfConcurrentThreads 参数的特殊之处在于,它定义了在一个完成端口上,同时允许执行的线程数量。

理想情况下,我们希望每个处理器各自负责一个线程的运行,为完成端口提供服务,避免过于频繁的线程“场景”(即线程上下文)切换。

若将该参数设为 0,表明系统内安装了多少个处理器,便允许同时运行多少个工作者线程!可用下述代码创建一个 I/O 完成端口:HANDLE CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);★1、工作者线程与完成端口成功创建一个完成端口后,便可开始将套接字句柄与其关联到一起。

但在关联套接字之前,首先必须创建一个或多个“工作者线程”,以便在 I/O 请求投递给完成端口后,为完成端口提供服务。

在这个时候,大家或许会觉得奇怪,到底应创建多少个线程,以便为完成端口提供服务呢?在此,要记住的一点,我们调用 CreateIoComletionPort 时指定的并发线程数量,与打算创建的工作者线程数量相比,它们代表的不是同一件事情。

CreateIoCompletionPort 函数的 NumberOfConcurrentThreads 参数明确指示系统:在一个完成端口上,一次只允许 n 个工作者线程运行。

假如在完成端口上创建的工作者线程数量超出 n 个,那么在同一时刻,最多只允许n个线程运行。

但实际上,在一段较短的时间内,系统有可能超过这个值,但很快便会把它减少至事先在 CreateIoCompletionPort 函数中设定的值。

那么,为何实际创建的工作者线程数量有时要比 CreateIoCompletionPort 函数设定的多一些呢?这样做有必要吗?这主要取决于应用程序的总体设计情况。

假定我们的某个工作者线程调用了一个函数,比如 Sleep 或 WaitForSingleObject,进入了暂停(锁定或挂起)状态,那么允许另一个线程代替它的位置。

换言之,我们希望随时都能执行尽可能多的线程;当然,最大的线程数量是事先在CreateIoCompletonPort 调用里设定好的。

这样一来,假如事先预计到自己的线程有可能暂时处于停顿状态,那么最好能够创建比 CreateIoCompletonPort 的 NumberOfConcurrentThreads 参数的值多的线程,以便到时候充分发挥系统的潜力。

==========================================每一种模型适用于一种特定的应用场景。

程序员应该对自己的应用需求非常明确,综合考虑到程序的扩展性和可移植性等因素,作出自己的选择。

==============================================█“完成端口”模型是迄今为止最复杂的一种 I/O 模型。

但是,若一个应用程序同时需要管理很多的套接字,那么采用这种模型,往往可以达到最佳的系统性能!但缺点是,该模型只适用于Windows NT 和 Windows 2000 以上版本的操作系统。

█因其设计的复杂性,只有在你的应用程序需要同时管理数百乃至上千个套接字的时候,而且希望随着系统内安装的CPU数量的增多,应用程序的性能也可以线性提升,才应考虑采用“完成端口”模型。

█从本质上说,完成端口模型要求我们创建一个 Win32 完成端口对象,通过指定数量的线程,对重叠 I/O 请求进行管理,以便为已经完成的重叠 I/O 请求提供服务。

█※※※大家可以这样理解,一个完成端口其实就是一个完成 I/O 的通知队列,由操作系统把已经完成的重叠 I/O 请求的通知放入这个队列中。

当某项 I/O 操作一旦完成,某个可以对该操作结果进行处理的工作者线程就会收到一则通知,工作者线程再去做一些其他的善后工作,比如:将收到的数据进行显示,等等。

而套接字在被创建后,可以在任何时候与某个完成端口进行关联。

※※※通常情况下,我们会在应用程序中创建一定数量的工作者线程来处理这些通知。

线程数量取决于应用程序的特定需要。

理想的情况是,线程数量等于处理器的数量,不过这也要求任何线程都不应该执行诸如同步读写、等待事件通知等阻塞型的操作,以免线程阻塞。

每个线程都将分到一定的CPU时间,在此期间该线程可以运行,然后另一个线程将分到一个时间片并开始执行。

如果某个线程执行了阻塞型的操作,操作系统将剥夺其未使用的剩余时间片并让其它线程开始执行。

也就是说,前一个线程没有充分使用其时间片,当发生这样的情况时,应用程序应该准备其它线程来充分利用这些时间片。

█使用这种模型之前,首先要创建一个 I/O 完成端口对象,用它面向任意数量的套接字句柄,管理多个 I/O 请求。

要做到这一点,需要调用 CreateCompletionPort 函数,其定义如下:HANDLE WINAPI CreateIoCompletionPort(__in HANDLE FileHandle,__in HANDLE ExistingCompletionPort,__in ULONG_PTR CompletionKey,__in DWORD NumberOfConcurrentThreads);要注意该函数有两个功能:●用于创建一个完成端口对象;●将一个句柄同完成端口对象关联到一起。

如果仅仅为了创建一个完成端口对象,唯一注意的参数便是NumberOfConcurrentThreads(并发线程的数量),前面三个参数可忽略。

NumberOfConcurrentThreads 参数的特殊之处在于,它定义了在一个完成端口上,同时允许执行的线程数量。

理想情况下,我们希望每个处理器各自负责一个线程的运行,为完成端口提供服务,避免过于频繁的线程“场景”(即线程上下文)切换。

若将该参数设为 0,表明系统内安装了多少个处理器,便允许同时运行多少个工作者线程!可用下述代码创建一个 I/O 完成端口:HANDLE CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);★1、工作者线程与完成端口成功创建一个完成端口后,便可开始将套接字句柄与其关联到一起。

但在关联套接字之前,首先必须创建一个或多个“工作者线程”,以便在 I/O 请求投递给完成端口后,为完成端口提供服务。

在这个时候,大家或许会觉得奇怪,到底应创建多少个线程,以便为完成端口提供服务呢?在此,要记住的一点,我们调用 CreateIoComletionPort 时指定的并发线程数量,与打算创建的工作者线程数量相比,它们代表的不是同一件事情。

CreateIoCompletionPort 函数的 NumberOfConcurrentThreads 参数明确指示系统:在一个完成端口上,一次只允许 n 个工作者线程运行。

假如在完成端口上创建的工作者线程数量超出 n 个,那么在同一时刻,最多只允许n个线程运行。

相关文档
最新文档