版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領
文檔簡介
1/1完成端口加線程池技術實現(xiàn)WinSock異步I/O模型[5]完成端口-CompletionPort
如果你想在Windows平臺上構建服務器應用,那么I/O模型是你必須考慮的。Windows操作系統(tǒng)提供了五種I/O模型,分別是:
■選擇(select);
■異步選擇(WSAAsyncSelect);
■事件選擇(WSAEventSelect);
■重疊I/O(OverlappedI/O);
■完成端口(CompletionPort)。
每一種模型適用于一種特定的應用場景。程序員應該對自己的應用需求非常明確,綜合考慮到程序的擴展性和可移植性等因素,作出自己的選擇。
==============================================
█“完成端口”模型是迄今為止最復雜的一種I/O模型。但是,若一個應用程序同時需要管理很多的套接字,
那么采用這種模型,往往可以達到最佳的系統(tǒng)性能!但缺點是,該模型只適用于WindowsNT和Windows2000以上版本的操作系統(tǒng)。
█因其設計的復雜性,只有在你的應用程序需要同時管理數(shù)百乃至上千個套接字的時候,而且希望隨著系統(tǒng)內(nèi)安裝的CPU數(shù)量的增多,
應用程序的性能也可以線性提升,才應考慮采用“完成端口”模型。
█從本質上說,完成端口模型要求我們創(chuàng)建一個Win32完成端口對象,通過指定數(shù)量的線程,
對重疊I/O請求進行管理,以便為已經(jīng)完成的重疊I/O請求提供服務。
█※※※大家可以這樣理解,一個完成端口其實就是一個完成I/O的通知隊列,由操作系統(tǒng)把已經(jīng)完成的重疊I/O請求的通知放入這個隊列中。
當某項I/O操作一旦完成,某個可以對該操作結果進行處理的工線程就會收到一則通知,工線程再去做一些其他的善后工作,
比如:將收到的數(shù)據(jù)進行顯示,等等。而套接字在被創(chuàng)建后,可以在任何時候與某個完成端口進行關聯(lián)。※※※
通常情況下,我們會在應用程序中創(chuàng)建一定數(shù)量的工線程來處理這些通知。線程數(shù)量取決于應用程序的特定需要。理想的情況是,線程數(shù)量等于處理器的數(shù)量,不過這也要求任何線程都不應該執(zhí)行諸如同步讀寫、等待事件通知等阻塞型的操作,以免線程阻塞。每個線程都將分到一定的CPU時間,在此期間該線程可以運行,然后另一個線程將分到一個時間片并開始執(zhí)行。如果某個線程執(zhí)行了阻塞型的操作,操作系統(tǒng)將剝奪其未使用的剩余時間片并讓其它線程開始執(zhí)行。也就是說,前一個線程沒有充分使用其時間片,當發(fā)生這樣的情況時,應用程序應該準備其它線程來充分利用這些時間片。
█使用這種模型之前,首先要創(chuàng)建一個I/O完成端口對象,用它面向任意數(shù)量的套接字句柄,管理多個I/O請求。
要做到這一點,需要調用CreateCompletionPort函數(shù),其定義如下:
HANDLEWINAPICreateIoCompletionPort(
__inHANDLEFileHandle,
__inHANDLEExistingCompletionPort,
__inULONG_PTRCompletionKey,
__inDWORDNumberOfConcurrentThreads
);
要注意該函數(shù)有兩個功能:
●用于創(chuàng)建一個完成端口對象;
●將一個句柄同完成端口對象關聯(lián)到一起。
如果僅僅為了創(chuàng)建一個完成端口對象,唯一注意的參數(shù)便是NumberOfConcurrentThreads(并發(fā)線程的數(shù)量),前面三個參數(shù)可忽略。
NumberOfConcurrentThreads參數(shù)的特殊之處在于,它定義了在一個完成端口上,同時允許執(zhí)行的線程數(shù)量。
理想情況下,我們希望每個處理器各自負責一個線程的運行,為完成端口提供服務,避免過于頻繁的線程“場景”(即線程上下文)切換。
若將該參數(shù)設為0,表明系統(tǒng)內(nèi)安裝了多少個處理器,便允許同時運行多少個工線程!可用下述代碼創(chuàng)建一個I/O完成端口:
HANDLECompletionPort=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
★1、工線程與完成端口
成功創(chuàng)建一個完成端口后,便可開始將套接字句柄與其關聯(lián)到一起。但在關聯(lián)套接字之前,首先必須創(chuàng)建一個或多個“工線程”,
以便在I/O請求投遞給完成端口后,為完成端口提供服務。在這個時候,大家或許會覺得奇怪,到底應創(chuàng)建多少個線程,以便為完成端口提供服務呢?
在此,要記住的一點,我們調用CreateIoComletionPort時指定的并發(fā)線程數(shù)量,與打算創(chuàng)建的工線程數(shù)量相比,它們代表的不是同一件事情。
CreateIoCompletionPort函數(shù)的NumberOfConcurrentThreads參數(shù)明確指示系統(tǒng):
在一個完成端口上,一次只允許n個工線程運行。假如在完成端口上創(chuàng)建的工線程數(shù)量超出n個,那么在同一時刻,最多只允許n個線程運行。
但實際上,在一段較短的時間內(nèi),系統(tǒng)有可能超過這個值,但很快便會把它減少至事先在CreateIoCompletionPort函數(shù)中設定的值。
那么,為何實際創(chuàng)建的工線程數(shù)量有時要比CreateIoCompletionPort函數(shù)設定的
多一些呢?這樣做有必要嗎?
這主要取決于應用程序的總體設計情況。假定我們的某個工線程調用了一個函數(shù),比如Sleep或WaitForSingleObject,
進入了暫停(鎖定或掛起)狀態(tài),那么允許另一個線程代替它的位置。換言之,我們
希望隨時都能執(zhí)行盡可能多的線程;
當然,最大的線程數(shù)量是事先在CreateIoCompletonPort調用里設定好的。這樣一來,假如事先預計到自己的線程有可能暫時處于停頓狀態(tài),
那么最好能夠創(chuàng)建比CreateIoCompletonPort的NumberOfConcurrentThreads參數(shù)的值多的線程,以便到時候充分發(fā)揮系統(tǒng)的潛力。
==========================================
每一種模型適用于一種特定的應用場景。程序員應該對自己的應用需求非常明確,
綜合考慮到程序的擴展性和可移植性等因素,作出自己的選擇。
==============================================
█“完成端口”模型是迄今為止最復雜的一種I/O模型。但是,若一個應用程序同時
需要管理很多的套接字,
那么采用這種模型,往往可以達到最佳的系統(tǒng)性能!但缺點是,該模型只適用于WindowsNT和Windows2000以上版本的操作系統(tǒng)。
█因其設計的復雜性,只有在你的應用程序需要同時管理數(shù)百乃至上千個套接字的時候,而且希望隨著系統(tǒng)內(nèi)安裝的CPU數(shù)量的增多,
應用程序的性能也可以線性提升,才應考慮采用“完成端口”模型。
█從本質上說,完成端口模型要求我們創(chuàng)建一個Win32完成端口對象,通過指定數(shù)量的線程,
對重疊I/O請求進行管理,以便為已經(jīng)完成的重疊I/O請求提供服務。
█※※※大家可以這樣理解,一個完成端口其實就是一個完成I/O的通知隊列,由操作系統(tǒng)把已經(jīng)完成的重疊I/O請求的通知放入這個隊列中。
當某項I/O操作一旦完成,某個可以對該操作結果進行處理的工線程就會收到一則通知,工線程再去做一些其他的善后工作,
比如:將收到的數(shù)據(jù)進行顯示,等等。而套接字在被創(chuàng)建后,可以在任何時候與某個完成端口進行關聯(lián)?!?/p>
通常情況下,我們會在應用程序中創(chuàng)建一定數(shù)量的工線程來處理這些通知。線程數(shù)量取決于應用程序的特定需要。理想的情況是,線程數(shù)量等于處理器的數(shù)量,不過這也要求任何線程都不應該執(zhí)行諸如同步讀寫、等待事件通知等阻塞型的操作,以免線程阻塞。每個線程都將分到一定的CPU時間,在此期間該線程可以運行,然后另一個線程將分到一個時間片并開始執(zhí)行。如果某個線程執(zhí)行了阻塞型的操作,操作系統(tǒng)將剝奪其未使用的剩余時間片并讓其它線程開始執(zhí)行。也就是說,前一個線程沒有充分使用其時間片,當發(fā)生這樣的情況時,應用程序應該準備其它線程來充分利用這些時間片。
█使用這種模型之前,首先要創(chuàng)建一個I/O完成端口對象,用它面向任意數(shù)量的套接字句柄,管理多個I/O請求。
要做到這一點,需要調用CreateCompletionPort函數(shù),其定義如下:
HANDLEWINAPICreateIoCompletionPort(
__inHANDLEFileHandle,
__inHANDLEExistingCompletionPort,
__inULONG_PTRCompletionKey,
__inDWORDNumberOfConcurrentThreads
);
要注意該函數(shù)有兩個功能:
●用于創(chuàng)建一個完成端口對象;
●將一個句柄同完成端口對象關聯(lián)到一起。
如果僅僅為了創(chuàng)建一個完成端口對象,唯一注意的參數(shù)便是NumberOfConcurrentThreads(并發(fā)線程的數(shù)量),前面三個參數(shù)可忽略。
NumberOfConcurrentThreads參數(shù)的特殊之處在于,它定義了在一個完成端口上,同時允許執(zhí)行的線程數(shù)量。
理想情況下,我們希望每個處理器各自負責一個線程的運行,為完成端口提供服務,避免過于頻繁的線程“場景”(即線程上下文)切換。
若將該參數(shù)設為0,表明系統(tǒng)內(nèi)安裝了多少個處理器,便允許同時運行多少個工線程!可用下述代碼創(chuàng)建一個I/O完成端口:
HANDLECompletionPort=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
★1、工線程與完成端口
成功創(chuàng)建一個完成端口后,便可開始將套接字句柄與其關聯(lián)到一起。但在關聯(lián)套接字之前,首先必須創(chuàng)建一個或多個“工線程”,
以便在I/O請求投遞給完成端口后,為完成端口提供服務。在這個時候,大家或許會覺得奇怪,到底應創(chuàng)建多少個線程,以便為完成端口提供服務呢?
在此,要記住的一點,我們調用CreateIoComletionPort時指定的并發(fā)線程數(shù)量,與打算創(chuàng)建的工線程數(shù)量相比,它們代表的不是同一件事情。
CreateIoCompletionPort函數(shù)的NumberOfConcurrentThreads參數(shù)明確指示系統(tǒng):
在一個完成端口上,一次只允許n個工線程運行。假如在完成端口上創(chuàng)建的工線程數(shù)量超出n個,那么在同一時刻,最多只允許n個線程運行。
但實際上,在一段較短的時間內(nèi),系統(tǒng)有可能超過這個值,但很快便會把它減少至事
先在CreateIoCompletionPort函數(shù)中設定的值。
那么,為何實際創(chuàng)建的工線程數(shù)量有時要比CreateIoCompletionPort函數(shù)設定的
多一些呢?這樣做有必要嗎?
這主要取決于應用程序的總體設計情況。假定我們的某個工線程調用了一個函數(shù),比如Sleep或WaitForSingleObject,
進入了暫停(鎖定或掛起)狀態(tài),那么允許另一個線程代替它的位置。換言之,我們
希望隨時都能執(zhí)行盡可能多的線程;
當然,最大的線程數(shù)量是事先在CreateIoCompletonPort調用里設定好的。這樣一來,假如事先預計到自己的線程有可能暫時處于停頓狀態(tài),
那么最好能夠創(chuàng)建比CreateIoCompletonPort的NumberOfConcurrentThreads參數(shù)的值多的線程,以便到時候充分發(fā)揮系統(tǒng)的潛力。
==========================================
一旦在完成端口上擁有足夠多的工線程來為I/O請求提供服務,便可著手將套接
字句柄同完成端口關聯(lián)到一起。
這要求我們在一個現(xiàn)有的完成端口上,調用CreateIoCompletionPort函數(shù),同時為前
三個參數(shù)—FileHandle,ExistingCompletionPort和CompletionKey—提供套接字的信息。
●FileHandle參數(shù)指定一個要同完成端口關聯(lián)在一起的套接字句柄;
●ExistingCompletionPort參數(shù)指定的是一個現(xiàn)有的完成端口;
●CompletionKey(完成鍵)參數(shù)指定與某個套接字句柄關聯(lián)在一起的“單句柄數(shù)據(jù)”,可將其作為指向一個數(shù)據(jù)結構的指針,
在此數(shù)據(jù)結構中,同時包含了套接字的句柄,以及與套接字有關的其他信息,如IP地址等。為完成端口提供服務的線程函數(shù)可通過這個參數(shù),取得與套接字句柄有關的信息。
根據(jù)目前,首先來構建一個基本的應用程序框架。下面的程序清單向
大家闡述了如何使用完成端口模型,來開發(fā)一個服務器應用。在這個程序中,
我們按照以下步驟進行:
1)創(chuàng)建一個完成端口,第四個參數(shù)保持為0,指定在完成端口上,每個處理器一次只允許執(zhí)行一個工線程;
2)判斷系統(tǒng)內(nèi)到底安裝了多少個處理器;
3)創(chuàng)建工線程,根據(jù)步驟2)得到的處理器信息,在完成端口上,為已完成的I/O請求提供服務,在這個簡單的例子中,我們?yōu)槊總€處理器都只創(chuàng)建一個工線程。
這是由于事先已預計到,到時不會有任何線程進入“掛起”狀態(tài),造成由于線程數(shù)量的不足,而使處理器空閑的局面(沒有足夠的線程可供執(zhí)行)。
調用CreateThread函數(shù)時,必須同時提供一個工例程,由線程在創(chuàng)建好執(zhí)行;
4)準備好一個監(jiān)聽套接字,在端口9527上監(jiān)聽進入的連接請求;
5)使用accept函數(shù),接受進入的連接請求;
6)創(chuàng)建一個數(shù)據(jù)結構,用于容納“單句柄數(shù)據(jù)”,同時在結構中存入接受的套接字句柄;
7)調用CreateIoCompletionPort函數(shù),將從accept返回的新套接字句柄同完成端口關聯(lián)到一起,
通過完成鍵(CompletionKey)參數(shù),將單句柄數(shù)據(jù)結構傳遞給CreateIoCompletionPort函數(shù);
8)開始在已接受的連接上進行I/O操作,在此,我們希望通過重疊I/O機制,在新建的套接字上投遞一個或多個異步WSARecv或WSASend請求。
這些I/O請求完成后,一個工線程會為I/O請求提供服務,同時繼續(xù)處理未來的其他I/O請求,
稍后便會在步驟3)指定的工例程中,體驗到這一點;
9)重復步驟5)~8),直至服務器中止。
代碼如下:
HANDLECompletionPort;
WSADATAwsd;
SYSTEM_INFOSystemInfo;
SOCKADDR_INInternetAddr;
SOCKETListen;
inti;
typedefstruct_PER_HANDLE_DATA
{
SOCKETSocket;
SOCKADDR_STORAGEClientAddr;
//Otherinformationusefultobeassociatedwiththehandle}PER_HANDLE_DATA,*LPPER_HANDLE_DATA;
//LoadWinsock
StartWinsock(MAKEWORD(2,2),
//Step1:
//創(chuàng)建一個完成端口
CompletionPort=CreateIoCompletionPort(
INVALID_HANDLE_VALUE,NULL,0,0);
//Step2:
//判斷系統(tǒng)內(nèi)到底安裝了多少個處理器
GetSystemInfo(
//Step3:
//根據(jù)處理器的數(shù)量創(chuàng)建工線程
for(i=0;iSocket=Accept;
memcpy(
//Step7:
//調用CreateIoCompletionPort函數(shù),將從accept返回的新套接字句柄同完成端口關聯(lián)到一起
CreateIoCompletionPort((HANDLE)Accept,
CompletionPort,(DWORD)PerHandleData,0);
//Step8:
//開始在已接受的連接上進行I/O操作
WSARecv(...);
}
DWORDWINAPIServerWorkerThread(LPVOIDlpParam)
{
//Therequirementsfortheworkerthreadwillbe
//discussedlater.
return0;
}
★2、完成端口和重疊I/O(工線程要做的事情)
將套接字句柄與一個完成端口關聯(lián)在一起后,便可投遞發(fā)送與接收請求,開始對I/O請求的處理。
接下來,可開始依賴完成端口,來接收有關I/O操作完成情況的通知。
從本質上說,完成端口模型利用了Win32重疊I/O機制。在這種機制中,象WSASend和WSARecv這樣的WinsockAPI調用會立即返回。
此時,需要由我們的應用程序負責在以后的某個時間,通過一個OVERLAPPED結構,來接收之前調用請求的結果。
在完成端口模型中,要想做到這一點,需要使用GetQueuedCompletionStatus(獲取
排隊完成狀態(tài))函數(shù),
讓一個或多個工線程在完成端口上等待I/O請求完成的通知。該函數(shù)的定義如下:BOOLWINAPIGetQueuedCompletionStatus(
__inHANDLECompletionPort,
__outLPDWORDlpNumberOfBytes,
__outPULONG_PTRlpCompletionKey,
__outLPOVERLAPPED*lpOverlapped,
__inDWORDdwMilliseconds
);
●CompletionPort參數(shù)對應于要在上面等待的完成端口;
●lpNumberOfBytes參數(shù)負責在完成了一次I/O操作后(如:WSASend或WSARecv),接收實際傳輸?shù)淖止?jié)數(shù)。
●lpCompletionKey參數(shù)為原先傳遞給CreateIoCompletionPort函數(shù)第三個參數(shù)“單句柄數(shù)據(jù)”,如我們早先所述,大家最好將套接字句柄保存在這個“鍵”(Key)中。
●lpOverlapped參數(shù)用于接收完成I/O操作的重疊結果。這實際是一個相當重要的參數(shù),因為可用它獲取每個I/O操作的數(shù)據(jù)。
●dwMilliseconds參數(shù)用于指定希望等待一個完成數(shù)據(jù)包在完成端口上出現(xiàn)的時間,即,超時時間。假如將其設為INFINITE,會一直等待下去。
★3、“單句柄數(shù)據(jù)”和單I/O操作數(shù)據(jù)
一個工線程從GetQueuedCompletionStatus函數(shù)接收到I/O完成通知后,在lpCompletionKey和lpOverlapped參數(shù)中,
會包含一些重要的套接字信息。利用這些信息,可通過完成端口,繼續(xù)在一個套接字
上進行其他的處理。
通過這些參數(shù),可獲得兩方面重要的套接字數(shù)據(jù):“單句柄數(shù)據(jù)”以及單I/O操作數(shù)據(jù)。
其中,lpCompletionKey參數(shù)包含了“單句柄數(shù)據(jù)”,因為在一個套接字首次與完成端口關聯(lián)到一起的時候,
那些數(shù)據(jù)便與一個特定的套接字句柄對應起來了。這些數(shù)據(jù)正是我們在調用CreateIoCompletionPort函數(shù)時候,通過CompletionKey參數(shù)傳遞的。
通常情況下,應用程序會將與I/O請求有關的套接字句柄及其他的一些相關信息保存在這里;
lpOverlapped參數(shù)則包含了一個OVERLAPPED結構,在它后面跟隨“單I/O操作數(shù)據(jù)”。
單I/O操作數(shù)據(jù)可以是追加到一個OVERLAPPED結構末尾的、任意數(shù)量的字節(jié)。
假如一個函數(shù)要求用到一個OVERLAPPED結構,我們便必須將這樣的一個結構傳遞進去,以滿足它的要求。
要想做到這一點,一個簡單的方法是定義一個結構,然后將OVERLAPPED結構作為新結構的第一個元素使用。
舉個例子來說,可定義下述數(shù)據(jù)結構,實現(xiàn)對單I/O操作數(shù)據(jù)的管理:
typedefstruct
{
OVERLAPPEDOverlapped;
WSABUFDataBuf;
charszBuffer[DATA_BUF_SIZE];
intOperationType;
}PER_IO_OPERATION_DATA;
該結構演示了通常與I/O操作關聯(lián)的一些重要的數(shù)據(jù)元素,比如剛才完成的那個I/O操作的類型(發(fā)送或接收請求),用OperationType字段表示,
同時,用于已完成I/O操作數(shù)據(jù)的緩沖區(qū)szBuffer也是非常有用的。如果想調用一個WinsockAPI函數(shù)(如:WSASend、WSARecv),要為其分配一個OVERLAPPED結構,
這時,就可以將我們的結構強制轉換成一個OVERLAPPED指針,或者從結構中將OVERLAPPED元素的地址取出來。如下例所示:
PER_IO_OPERATION_DATAPerIoData;
……
//可以這樣調用:
WSARecv(socket,...,(OVERLAPPED*)
//也可以這樣調用:
WSARecv(socket,...,
在工作線程的后面部分,等GetQueuedCompletionStatus函數(shù)返回了一個重疊結構(和完成鍵)后,
便可通過OperationType成員,看出到底是哪個操作投遞到了這個句柄之上(只需將
返回的重疊結強制轉換為自己的PER_IO_OPERATION_DATA結構)。
對單I/O操作數(shù)據(jù)來說,它最大的一個優(yōu)點便是允許我們在同一個句柄上,同時管理
多個I/O操作(讀/寫,多個讀,多個寫,等等)。
DWORDWINAPIServerWorkerThread(LPVOIDCompletionPortID)
{
HANDLECompletionPort=(HANDLE)CompletionPortID;
DWORDBytesTransferred;
LPOVERLAPPEDOverlapped;
LPPER_HANDLE_DATAPerHandleData;
LPPER_IO_DATAPerIoData;
DWORDSendBytes,RecvBytes;
DWORDFlags;
while(TRUE)
{
//WaitforI/Otocompleteonanysocket
//associatedwiththecompletionport
ret=GetQueuedCompletionStatus(CompletionPort,
//Firstchecktoseeifanerrorhasoccurred
//onthesocket;ifso,closethe
//socketandcleanuptheper-handledata
//andper-I/Ooperationdataassociatedwith
//thesocket
if(BytesTransferred==0
GlobalFree(PerHandleData);
GlobalFree(PerIoData);
continue;
}
//ServicethecompletedI/Orequest.Youcan
//determinewhichI/Orequesthasjust
//completedbylookingattheOperationType
//fieldcontainedintheper-I/Ooperationdata.
if(PerIoData->OperationType==RECV_POSTED){
//Dosomethingwiththereceiveddata
//inPerIoData->Buffer
}
//PostanotherWSASendorWSARecvoperation.//Asanexample,wewillpostanotherWSARecv()//I/Ooperation.
Flags=0;
//Setuptheper-I/Ooperationdataforthenext//overlappedcall
ZeroMemory(
PerIoData->DataBuf.len=DATA_BUFSIZE;
PerIoData->DataBuf.buf=PerIoData->Buffer;
PerIoData->OperationType=RECV_POSTED;
WSARecv(PerHandleData->Socket,
}
★4、正確地關閉I/O完成端口
如何正確地關閉I/O完成端口,特別是同時運行了一個或多個線程,在幾個不同的套
接字上執(zhí)行I/O操作的時候。
要避免的一個重要問題是在進行重疊I/O操作的同時,強行釋放一個OVERLAPPED結構。
要想避免出現(xiàn)這種情況,最好的辦法是針對每個套接字句柄,調用closesocket函數(shù),任何尚未進行的重疊I/O操作都會完成。一旦所有套接字句柄都已關閉,
便需在完成端口上,終止所有工線程的運行。要想做到這一點,需要使用PostQueuedCompletionStatus函數(shù),向每個工線程都發(fā)送一個特殊的完成數(shù)據(jù)包。
該函數(shù)會指示每個線程都“立即結束并退出”。下面是PostQueuedCompletionStatus函數(shù)的定義:
BOOLWINAPIPostQueuedCompletionStatus(
__inHANDLECompletionPort,
__inDWORDdwNumberOfBytesTransferred,
__inULONG_PTRdwCompletionKey,
__inLPOVERLAPPEDlpOverlapped
);
●CompletionPort參數(shù)指定想向其發(fā)送一個完成數(shù)據(jù)包的完成端口對象;
●而就dwNumberOfBytesTransferred、dwCompletionKey和lpOverlapped三個參數(shù)
來說,每一個都允許我們指定一個值,
直接傳遞給GetQueuedCompletionStatus函數(shù)中對應的參數(shù)。這樣一來,一個工線程收到傳遞過來的三個GetQueuedCompletionStatus函數(shù)參數(shù)后,
便可根據(jù)由這三個參數(shù)的某一個設置的特殊值,決定何時或者應該怎樣退出。
例如,可用dwCompletionPort參數(shù)傳遞0值,而一個工線程會將其解釋成中止
指令。
一旦所有工線程都已關閉,便可使用CloseHandle函數(shù),關閉完成端口,最終安
全退出程序。
==========================================
1、線程池的基本原理
在傳統(tǒng)服務器架構中,常常是有一個總的監(jiān)聽線程監(jiān)聽有沒有新的用戶連接服務器,每當有一個新的用戶連接進入,服務器端就開啟一個新的線程去處理這個用戶的請求,與其進行數(shù)據(jù)的收發(fā)。
這個線程只服務于這個用戶,當用戶與服務器端關閉連接以后,服務器端才銷毀這個線程。然而頻繁地開辟與銷毀線程極大地占用了系統(tǒng)的資源。而且在大量用戶的情況下,少則1000,多則上萬,系統(tǒng)為了開辟和銷毀線程將浪費大量的時間和資源。
線程池技術很好的解決了這個問題,它的基本思想就是在程序開始時就在內(nèi)存中開辟一些線程,當有新的客戶請求到達時,
不是新創(chuàng)建一個線程為其服務,而是從“池子”中選擇一個空閑的線程為新的客戶請求服務,服務完畢后,線程不是退出,而是進入空閑線程池中。
通過對多個任務重用已經(jīng)存在的線程對象,降低了對線程對象創(chuàng)建和銷毀的開銷。當客戶請求時,線程對象已經(jīng)存在,可以提高請求的響應時間,從而整體地提高了系統(tǒng)服務的表現(xiàn)。
2、線程池的實現(xiàn)
如果大家有時間的話,可以自己實現(xiàn)一個高效的線程池,當然網(wǎng)上也有很多版本的線程池源代碼,大家可
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 專項采購附加合同(2024修訂版)版B版
- 二零二五年度新型環(huán)保材料研發(fā)與市場拓展合同3篇
- 專項個人施工合作合同2024版一
- 2025年度土地確權測量技術服務合同示例4篇
- 2025年度廠房設備租賃與技術創(chuàng)新合同范本4篇
- 2024年03月天津2024年天津銀行第五中心支行社會招考筆試歷年參考題庫附帶答案詳解
- 2025年度二零二五安保員聘用及企業(yè)安全管理制度修訂合同3篇
- 2024甲乙雙方電腦軟件購買與開發(fā)合同
- 2025年度醫(yī)療機構n95口罩消毒與再生利用合同范本3篇
- 2025年度籃球賽事官方安保人員配備與安全協(xié)議
- 大型活動聯(lián)合承辦協(xié)議
- 工程項目采購與供應鏈管理研究
- 2024年吉林高考語文試題及答案 (2) - 副本
- 拆除電纜線施工方案
- 搭竹架合同范本
- Neo4j介紹及實現(xiàn)原理
- 焊接材料-DIN-8555-標準
- 工程索賠真實案例范本
- 重癥醫(yī)學科運用PDCA循環(huán)降低ICU失禁性皮炎發(fā)生率品管圈QCC持續(xù)質量改進成果匯報
- 個人股權證明書
- 醫(yī)院運送工作介紹
評論
0/150
提交評論