Windows API一日一練(60)CreateIoCompletionPort和GetQueuedCompletionStatus函數__函數
來源:互聯網
上載者:User
在 Windows 系統裡,使用完成連接埠是高效能的方法之一,比如把完成連接埠使用到線程池和網路伺服器裡。現在就通過線程池的方法來介紹怎麼樣使用完成連接埠,高效能的伺服器以後再仔細地介紹怎麼樣構造它。其實完成連接埠是一個隊列,所有的線程都在等訊息出現,如果隊列裡有訊息,就每個線程去擷取一個訊息執行它。先用函數 CreateIoCompletionPort 來建立一個訊息佇列,然後使用 GetQueuedCompletionStatus 函數來從隊列擷取訊息,使用函數 PostQueuedCompletionStatus 來向隊列裡發送訊息。通過這三個函數就實現完成連接埠的訊息迴圈處理。 函數 CreateIoCompletionPort 、 GetQueuedCompletionStatus 、 PostQueuedCompletionStatus 聲明如下: WINBASEAPI __out HANDLE WINAPI CreateIoCompletionPort( __in HANDLE FileHandle, __in_opt HANDLE ExistingCompletionPort, __in ULONG_PTR CompletionKey, __in DWORD NumberOfConcurrentThreads ); WINBASEAPI BOOL WINAPI GetQueuedCompletionStatus( __in HANDLE CompletionPort, __out LPDWORD lpNumberOfBytesTransferred, __out PULONG_PTR lpCompletionKey, __out LPOVERLAPPED *lpOverlapped, __in DWORD dwMilliseconds ); WINBASEAPI BOOL WINAPI PostQueuedCompletionStatus( __in HANDLE CompletionPort, __in DWORD dwNumberOfBytesTransferred, __in ULONG_PTR dwCompletionKey, __in_opt LPOVERLAPPED lpOverlapped );
FileHandle 是關聯的檔案控制代碼。
ExistingCompletionPort 是已經存在的完成連接埠。
CompletionKey 是傳送給處理函數的參數。
NumberOfConcurrentThreads 是有多少個線程在訪問這個訊息佇列。
CompletionPort 是已經存在的完成連接埠。
lpCompletionKey 是傳送給處理函數的參數。
lpOverlapped 是傳送給處理函數的參數。
dwMilliseconds 是等待時間。
dwNumberOfBytesTransferred 是傳送了多少個位元組。 調用函數的例子如下: #001 #pragma once #002 #003 #include "Thread.h" #004 #005 #006 // 使用 IOCP 實現線程池。 #007 // 蔡軍生 2007/10/29 QQ:9073204 深圳 #008 class CThreadPools #009 { #010 public: #011 #012 CThreadPools(void) #013 { #014 m_nThreadCount = 2; #015 } #016 #017 ~CThreadPools(void) #018 { #019 } #020 #021 bool Init(void) #022 { #023 // 建立一個 IOCP 。
#024 m_hQueue = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, m_nThreadCount); #025 if (m_hQueue == NULL) #026 { #027 // 建立 IOCP 失敗。 #028 return false; #029 } #030 } #031 #032 int GetThreadCount(void) const #033 { #034 return m_nThreadCount; #035 } #036 #037 // 線程池處理的內容。 #038 DWORD Run(void) #039 { #040 DWORD dwBytesTransfered; #041 ULONG_PTR dwCompletionKey; #042 #043 OVERLAPPED* pOverlapped; #044 #045 // 等一個 IOCP 的訊息。
#046 while (GetQueuedCompletionStatus(m_hQueue, &dwBytesTransfered, &dwCompletionKey, &pOverlapped, INFINITE)) #047 { #048 if (pOverlapped == ((OVERLAPPED*) ((__int64) -1)) ) #049 { #050 // 退出。 #051 OutputDebugString(_T(" 退出 /r/n")); #052 break; #053 } #054 else #055 #056 { #057 WPARAM request = (WPARAM) dwCompletionKey; #058 #059 // 處理訊息。 #060 OutputDebugString(_T("GetQueuedCompletionStatus /r/n")); #061 } #062 } #063 #064 return 0; #065 } #066 #067 // 發送處理的訊息。 #068 bool QueueRequest(WPARAM wParam) #069 { #070 // 往 IOCP 裡發送一條訊息。
#071 if (!PostQueuedCompletionStatus(m_hQueue, 0, (ULONG_PTR) wParam, NULL)) #072 { #073 return false; #074 } #075 #076 return true; #077 } #078 #079 // 關閉所有線程。 #080 void Close(void) #081 { #082 for (int i = 0; i < m_nThreadCount; i++) #083 { #084 PostQueuedCompletionStatus(m_hQueue, 0, 0, (OVERLAPPED*) ((__int64) -1) ); #085 } #086 } #087 #088 protected: #089 // 接收訊息處理的隊列。 #090 HANDLE m_hQueue; #091 #092 // 線程個數。 #093 int m_nThreadCount; #094 }; #095 #096 ////////////////////////////////////////////////////////////////////////// #097 class CThreads : #098 public CThread #099 { #100 public: #101 CThreads(CThreadPools* pPool) #102 { #103 m_pPool = pPool; #104 } #105 virtual ~CThreads(void) #106 { #107 #108 } #109 #110 #111 protected: #112 // #113 // 線程運行函數。 #114 // 在這裡可以使用類裡的成員,也可以讓衍生類別實現更強大的功能。 #115 // 蔡軍生 2007/10/29 #116 virtual DWORD Run(void) #117 { #118 // #119 if (m_pPool) #120 { #121 return m_pPool->Run(); #122 } #123 #124 return -1; #125 } #126 #127 protected: #128 CThreadPools* m_pPool; #129 #130 };