執行緒池

執行緒池（thread pool）：一種執行緒使用模式。執行緒過多會帶來排程開銷，進而影響快取區域性性和整體效能。而執行緒池維護著多個執行緒，等待著監督管理者分配可併發執行的任務。這避免了在處理短時間任務時建立與銷燬執行緒的代價。執行緒池不僅能夠保證核心的充分利用，還能防止過分排程。可用執行緒數量應該取決於可用的併發處理器、處理器核心、記憶體、網路 sockets 等的數量。 例如，對於計算密集型任務，執行緒數上限一般取 CPU 邏輯核心數 + 2，執行緒數過多會導致額外的執行緒切換開銷。

任務排程以執行執行緒的常見方法是使用同步佇列，稱作任務佇列。池中的執行緒等待佇列中的任務，並把執行完的任務放入完成佇列中。

執行緒池模式一般分為兩種：HS/HA 半同步 / 半非同步模式、L/F 領導者與跟隨者模式。

半同步 / 半非同步模式又稱為生產者消費者模式，是比較常見的實現方式，比較簡單。分為同步層、佇列層、非同步層三層。同步層的主執行緒處理工作任務並存入工作佇列，工作執行緒從工作佇列取出任務進行處理，如果工作佇列為空，則取不到任務的工作執行緒進入掛起狀態。由於執行緒間有資料通訊，因此不適於大資料量交換的場合。
領導者跟隨者模式，線上程池中的執行緒可處在 3 種狀態之一：領導者 leader、追隨者 follower 或工作者 processor。任何時刻執行緒池只有一個領導者執行緒。事件到達時，領導者執行緒負責訊息分離，並從處於追隨者執行緒中選出一個來當繼任領導者，然後將自身設定為工作者狀態去處置該事件。處理完畢後工作者執行緒將自身的狀態置為追隨者。這一模式實現複雜，但避免了執行緒間交換任務資料，提高了 CPU cache 相似性。在 ACE (Adaptive Communication Environment) 中，提供了領導者跟隨者模式實現。

執行緒池的伸縮性對效能有較大的影響。

建立太多執行緒，將會浪費一定的資源，有些執行緒未被充分使用。
銷毀太多執行緒，將導致之後浪費時間再次建立它們。
建立執行緒太慢，將會導致長時間的等待，效能變差。
銷毀執行緒太慢，導致其它執行緒資源飢餓。

Windows API 的執行緒池函式

Windows 作業系統的 API 提供了一套執行緒池的實現介面。可以方便地建立、使用執行緒池。Windows 執行緒池 API 被設計為一組協同物件， 其中有些物件表示工作單位、計時器、非同步 I/O 等等。使用下述使用者模式的物件來管理執行緒池及相關的資料：

執行緒池物件（pool object）包含了一組工作執行緒（worker threads）。每個程序可以建立多個執行緒池物件，也可以直接使用程序預設的執行緒池。
回撥環境 (Threadpool Callback Environment) 執行緒池可以關聯多個回撥環境，回撥環境可單獨指定線上程池內的排程優先順序。
清理群（clean-up group）物件關聯於一個回撥環境。用於追溯 (track) 執行緒緩衝池回撥。每次建立執行緒池的 IO、work、timer、wait 等物件（呼叫 CreateThreadpool 等函式），會在 cleanup group 中增加一個成員。關閉執行緒池的 IO、work、timer、wait 等物件（呼叫 CloseThreadpool 等函式），會在 cleanup group 中刪除相應的成員。
執行緒池工作物件（work object） 由一個函式指標和一個被稱為上下文的 void 指標組成，執行緒池每次在執行時將 void 指標送入函式。可非同步多次投寄給執行緒池去執行它的回撥函式。實際上就是以非同步方式呼叫回撥函式。透過 SubmitThreadpoolWork 投寄工作物件到任務佇列。如果不建立新的工作物件，則不能更改函式和上下文。
執行緒池定時器物件（timer object）在定時器到期時投寄給執行緒池去執行它的回撥函式。 建立 (CreateThreadpoolTimer) 並設定 (SetThreadpoolTimer) 定時器物件。當定時器物件到期時，工作執行緒會執行定時器物件的回撥函式。
執行緒池等待物件（wait object）：在可等待控制代碼（waitable handle，可使用任何核心同步物件的控制代碼）被觸發（signaled）時或超時到期時，它的回撥函式被投寄給執行緒池去執行。建立 (CreateThreadpoolWait) 並設定 (SetThreadpoolWait) 等待物件。執行緒池內部的一個執行緒呼叫 WaitForMultipleObjects 並傳入由 SetThreadpoolWait 函式註冊的控制代碼，不斷地組成一個控制代碼組，同時將 Wait 函式的 bWaitAll 設為 FALSE，這樣當任何一個控制代碼被觸發，執行緒池就會被喚醒。因 WaitForMultipleObjects 不允許將同一個控制代碼傳入多次，因此必須確保不會用 SetThreadpoolWait 來多次註冊同一個控制代碼，但可以呼叫 DuplicationHandle 複製控制代碼並傳給 Set 函式。因 WaitForMultipleObjects 一次最多隻能等待 64 個核心物件，因此執行緒池實際上為每 64 個核心物件分配一個執行緒來等待，所以效率比較高。如果要等待超過 64 個以上的核心物件，系統會每 64 個核心物件，就開闢一個執行緒來等待這些核心物件。當執行緒池中一個執行緒呼叫了傳入的回撥函式，對應的等待項將進入 “不活躍” 狀態；這意味著如果在同一個核心物件被觸發後如果想再次呼叫這個回撥函式，需要呼叫 SetThreadpoolWait 再次註冊；如果傳入的 hObject 為 NULL，將把 pWaitItem 這個等待項從執行緒中移除。
執行緒池 I/O 物件把檔案控制代碼關聯到執行緒池的 I/O 完成埠（completion port）。當非同步 I/O 操作完成，一個工作執行緒取得操作的狀態並呼叫 I/O 物件的回撥函式。

相關的 API 函式：

CreateThreadpool 建立一個執行緒池資料結構
CloseThreadpool 關閉一個執行緒池
SetThreadpoolThreadMaximum 設定一個執行緒池的執行緒數量上限。預設執行緒池的最小數量為 1，最大數量為 500
SetThreadpoolThreadMinimum 設定一個執行緒池的執行緒數量下限
InitializeThreadpoolEnvironment 初始化一個回撥環境。作用是回撥環境結構體中的將 Version 設為 1，其餘為 0。
DestroyThreadpoolEnvironment 刪除回撥環境
SetThreadpoolCallbackPool 把指定的執行緒緩衝池關聯到指定的執行緒池回撥環境。建立執行緒池的 IO、work、timer、wait 等物件會關聯到一個回撥環境上。如果使用系統預設的回撥環境，需要自行負責回撥函式的 DLL 保持裝入狀態，自行管理執行緒池內的各種物件的生存期。執行緒池可以關聯多個回撥環境，回撥環境可單獨指定線上程池內的排程優先順序。
SetThreadpoolCallbackLibrary 指示在回撥函式未執行完的時候其所在的 DLL 庫不能解除安裝
SetThreadpoolCallbackPriority 設定回撥環境在所屬執行緒池內的優先順序
SetThreadpoolCallbackRunsLong 指示當前回撥函式將執行較長時間。這有助於執行緒池判斷是否建立新執行緒
CreateThreadpoolCleanupGroup 建立一個 cleanup group 資料結構，關聯到一個回撥環境上
SetThreadpoolCallbackCleanupGroup 把指定的 cleanup group 關聯到指定的回撥環境。第三個引數設定 CleanupGroupCancelCallback 回撥函式。當呼叫清理組的 CloseThreadpoolCleanupGroupmembers 函式，併為 bCancelPendingCallbacks 傳入 TRUE 來清除清理組時，如果此時尚有未被處理的工作項時，則這個回撥函式被呼叫，這個回掉函式的第一個引數 pvObjectContext 是透過 CreateThreadpool * 函式傳入的 pvContext，第二個引數 pvCleanupContext 是由 CloseThreadpoolCleanupGroupMembers 的 pvCleanupContext 引數傳入的。
CloseThreadpoolCleanupGroup 關閉一個 cleanup group 資料結構。cleanup group 不能包含任何成員。
CloseThreadpoolCleanupGroupMembers 把指定 cleanup group 的所有 work、timer、wait 等物件釋放掉。對於正在執行的回撥函式，會等待其執行完畢。引數 fCancelPendingCallbacks 確定是否尚未開始執行的任務執行。
CreateThreadpoolWork 建立一個執行緒池工作物件的資料結構
CloseThreadpoolWork 函式通知執行緒池該物件可釋放。
SubmitThreadpoolWork 投寄（post）一個工作物件到執行緒池中。一個工作執行緒將會呼叫執行這個工作物件的回撥函式。
TrySubmitThreadpoolCallback 請求執行緒池一個工作執行緒呼叫指定的回撥函式
CreateThreadpoolTimer 建立一個執行緒池定時器物件的資料結構
SetThreadpoolTimer 設定一個執行緒定時器物件的引數。當定時器到期時，這個定時器物件的回撥函式被放入任務佇列等待被一個工作執行緒執行。第三個引數設定週期性到時，不論之前放入任務佇列的回撥函式是否執行完畢，總是把回撥函式再一次放入任務佇列等待被執行。如果不希望一個定時器物件的回撥函式的多個例項併發重疊執行，可以不設定週期性到時引數，而在回撥函式末尾呼叫 SetThreadpoolTimer 重置這個定時器物件，起碼可以簡化除錯。如果呼叫 SetThreadpoolTimer 時當前定時器物件還沒有到期，則會修改該定時器物件的到期時間等屬性。第二個引數 pftDueTime 表示首次到時時間，如果為 NULL，則取消還未到時的定時器的下次到期，不再向任務佇列放入定時器物件的回撥函式，但已經在任務佇列中（正在被執行）的回撥函式仍會被執行。第四個引數是到時的容限上限，涉及定時器匯聚，如計時器 A 會在 5-7 微秒內被觸發，計時器 B 會在 6-8 微秒內。因時間有重疊，所以執行緒池只會喚醒一個執行緒來處理這兩個計時器，以減少用兩個執行緒呼叫時產生的額外的執行緒上下文切換的開銷。
IsThreadpoolTimerSet 判斷給定的定時器物件當前是否被設定
CreateThreadpoolWait 建立一個執行緒池等待（wait）物件的資料結構
SetThreadpoolWait 設定一個執行緒等待物件與一個可等待物件 (waitable object) 的控制代碼繫結並設定超時時間。當可等待物件的控制代碼被通知 (signaled) 或指定的超時到期，這個等待物件的回撥函式會被入列（queue）進入任務佇列中並等待被一個工作執行緒執行。如果可等待物件（即函式的第二個引數）的控制代碼被設定為 NULL，（由於可等待物件還沒有 signaled 所以）執行緒池等待物件的回撥函式還未放入任務佇列的都被取消，但已在任務佇列的回撥函式仍會被工作執行緒執行。注意不要多次使用 SetThreadpoolWait 來等待同一個 hObject。第三個引數 pftTimeout 指出執行緒池願意花的最長時間來等待核心物件觸發，0 是立即返回，負值為相對時間，正值為絕對時間，NULL 表示無限等待（執行緒池內部呼叫了 WaitForMultipleObjects）。
CloseThreadpoolWait 關閉一個執行緒等待物件，然後才能關閉可等待物件 (waitable object) 的控制代碼。
WaitForThreadpoolWaitCallbacks 等待指定的執行緒池等待物件執行完成或者取消還沒開始執行的執行緒池等待物件。
WaitForThreadpoolIoCallbacks 等待指定的執行緒池 IO 物件執行完成或者取消還沒開始執行的執行緒池 IO 物件。該函式須在另一個執行緒使用，而不能在回撥函式內部使用，因為這會造成死鎖。如果 bCancelPendingCallbacks 為 TRUE，那麼當請求完成的時候，回撥函式不會被呼叫（如果尚未被呼叫）。
WaitForThreadpoolTimerCallbacks 等待指定的執行緒池定時器物件執行完成或者取消還沒開始執行的執行緒池定時器物件。
WaitForThreadpoolWorkCallbacks 等待指定的執行緒池工作物件執行完成或者取消還沒開始執行的執行緒池工作物件。
CreateThreadpoolIo 建立一個 IO 完成物件，並繫結一個非同步 IO 的控制代碼。
CloseThreadpoolIo 釋放 IO 完成物件。應等待所有 IO 操作完成，關閉 IO 檔案控制代碼後再呼叫本函式。解除 IO 物件（工作項）與執行緒池的關聯。
StartThreadpoolIo 初始化非同步 IO 操作前應先呼叫本函式，否則執行緒池會忽略 IO 操作的完成並記憶體洩露。
CancelThreadpoolIo 在 IO 失敗或者 IO 直接同步完成時，取消對執行緒池的通知（notification）
CallbackMayRunLong 回撥函式通知系統需要執行較長時間。只能在呼叫執行緒的回撥函數里使用。返回 TRUE 時，說明執行緒池還有其他執行緒可供使用。FALSE 則相反。
DisassociateCurrentThreadFromCallback 表示與回撥函式關聯的工作項在 “邏輯上” 完成了，執行當前回調函式的執行緒與初始化當前回撥函式的物件去關聯。這使得所有等待當前回撥函式完成的執行緒被釋放。任何由於呼叫 WaitForThreadpool*Callbacks（如 WaitForThreadpoolIoCallbacks）而被阻塞的執行緒能早一些返回，而不必等到執行緒從回撥函式中結束時才返回。
下述函式與回撥函式實體指標 PTPCALLBACKINSTANCE 有關，用於在回撥函式內設定當該函式結束時的動作。注意只能有一個動作在回撥函式結束後被執行，不能多次呼叫下述函式，否則最後一次呼叫的函式會覆蓋之前呼叫的下述函式。當執行緒呼叫回撥函式時，Windows 會自動傳一個 pInstance 引數（型別 PTPCALLBACKINSTANCE) 給回撥函式，然後回撥函式將這個引數又傳給如下的函式，執行一些相應的終止操作：
FreeLibraryWhenCallbackReturns 當回撥函式返回的時候，執行緒池會自動呼叫 FreeLibrary，並在引數中傳入指定的 HMOUDLE。如果回撥函式是從 DLL 中載入的，這個函式尤為重要，因為當執行緒執行完畢後，回撥函式不能自己呼叫 FreeLibrary，否則回撥函式程式碼將從程序中清除，這樣當 FreeLibrary 試圖返回到回撥函式時，會引發訪問違規
LeaveCriticalSectionWhenCallbackReturns 當回撥函式返回時，執行緒池會自動呼叫 LeavCriticalSection，並在引數中傳入指定的 CRITCAL_SECTION 結構體。
ReleaseMutexWhenCallbackReturns 當回撥函式返回時，執行緒池會自動呼叫 ReleaseMutex，並在引數中傳入指定的 HANDLE
ReleaseSemaphoreWhenCallbackReturns 當回撥函式返回的時候，執行緒池會自動呼叫 ReleaseSemaphore，並在引數中傳入指定的 HANDLE
SetEventWhenCallbackReturns 當回撥函式返回的時候，執行緒池會自動呼叫 SetEvent，並在引數中傳入指定的 HANDLE

1.1 示例

示例程式 1 如下：

include

//

// Thread pool wait callback function template

//

VOID CALLBACK MyWaitCallback (PTPCALLBACKINSTANCE Instance, PVOID Parameter, PTPWAIT Wait, TPWAIT_RESULT WaitResult)

{

	// Instance, Parameter, Wait, and WaitResult not used in this example.

	UNREFERENCEDPARAMETER (Instance); 	UNREFERENCEDPARAMETER (Parameter);	UNREFERENCEDPARAMETER (Wait); 	UNREFERENCEDPARAMETER (WaitResult);

	// Do something when the wait is over.

	tprintf (T ("MyWaitCallback: wait is over.\n"));

}

//

// Thread pool timer callback function template

//

VOID CALLBACK MyTimerCallback (PTPCALLBACKINSTANCE Instance, PVOID Parameter, PTP_TIMER Timer)

{

	// Instance, Parameter, and Timer not used in this example.

	UNREFERENCEDPARAMETER (Instance); UNREFERENCEDPARAMETER (Parameter); UNREFERENCED_PARAMETER (Timer);

	// Do something when the timer fires.

	tprintf (T ("MyTimerCallback: timer has fired.\n"));

}

//

// This is the thread pool work callback function.

//

VOID CALLBACK MyWorkCallback (PTPCALLBACKINSTANCE Instance, PVOID Parameter, PTP_WORK Work)

{

	// Instance, Parameter, and Work not used in this example.

	UNREFERENCEDPARAMETER (Instance);UNREFERENCEDPARAMETER (Parameter);UNREFERENCED_PARAMETER (Work);

	// Do something when the work callback is invoked.

	tprintf (T ("MyWorkCallback: Task performed.\n"));

}

int main (void)

{

	PTP_WAIT Wait = NULL;

	PTPWAITCALLBACK waitcallback = MyWaitCallback;

	HANDLE hEvent = NULL;

	UINT i = 0;

	UINT rollback = 0;

	// Create an auto-reset event and initialized as nonsignaled.

	hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);

	if (NULL == hEvent) {

		// Error Handling

		return 0;

	}

	rollback = 1; // CreateEvent succeeded

	Wait = CreateThreadpoolWait (waitcallback,

		NULL, // 回撥函式的輸入引數

		NULL); // 使用預設的回撥環境

	if (NULL == Wait) {tprintf (T ("CreateThreadpoolWait failed. LastError: % u\n"),GetLastError );

		goto newwaitcleanup;

	}

	rollback = 2; // CreateThreadpoolWait succeeded

				 //must re-register the event with the wait object before signaling it each time to trigger the wait callback

				 //each time before signaling the event to trigger the wait callback.

	for (i = 0; i

關於 IO 執行緒池的一個示例：

include

void PressEnterToContinue

{std::cout ::max), '\n');

}

//////////////////////////////////////////////////////////////////////////

define QMLX_ALLOC (sz) HeapAlloc (GetProcessHeap ,0,sz)
define QMLXCALLOC (sz) HeapAlloc (GetProcessHeap ,HEAPZERO_MEMORY,sz)
define QMLX_SAFEFREE (p) if (NULL != p){HeapFree (GetProcessHeap ,0,p);p=NULL;}
define QMLX_ASSERT (s) if (!(s)){DebugBreak ;}
define QMLX_BEGINTHREAD (Fun,Param) CreateThread (NULL,0,\

(LPTHREADSTARTROUTINE) Fun,Param,0,NULL);

//////////////////////////////////////////////////////////////////////////

define MAXWRITEPERTHREAD 2 // 每個執行緒最大寫入次數
define MAXWRITETHREAD 2 // 寫入執行緒的數量
define OP_READ 0x01 // 讀操作
define OP_WRITE 0x02 // 寫操作

//#pragma pack (show)

// 單 IO 資料

typedef struct declspec (align (16)) _tagPerIoData {

	OVERLAPPED m_ol;

	HANDLE m_hFile; // 操作的檔案控制代碼

	DWORD mdwOp; // 操作型別，OPREAD 或 OP_WRITE

	LPVOID m_pData; // 操作的資料

	UINT m_nLen; // 操作的資料長度

	DWORD m_dwWrite; // 寫入的位元組數

	DWORD m_dwTimestamp; // 起始操作的時間戳

} PERIODATA, *PPERIODATA;

//IOCP 執行緒池回撥函式，實際就是完成通知的響應函式

VOID CALLBACK IOCPCallback (PTPCALLBACKINSTANCE pInstance, PVOID pvContext, PVOID pOverlapped,

	ULONG IoResult, ULONGPTR NumberOfBytesTransferred, PTPIO pio);

// 寫檔案的執行緒

DWORD WINAPI WriteThread (LPVOID lpParam);

// 當前操作的檔案物件的指標

LARGEINTEGER gliFilePointer = {0};

//IOCP 執行緒池

PTPIO gpThreadpoolIo = NULL;

//////////////////////////////////////////////////////////////////////////

// 獲取可模組的路徑名（路徑後含‘\’)

VOID GetAppPath (LPTSTR pszBuffer) {

	DWORD dwLen = 0;

	if (0 == (dwLen = GetModuleFileName (NULL, pszBuffer, MAX_PATH)))

		return;

	for (DWORD i = dwLen; i> 0; i--) {if ('\\' == pszBufferi) {

			pszBufferi + 1 = '\0';

			break;

		}

	}

}

int tmain {tsetlocale (LCALL, T ("chs"));

	TCHAR pFileNameMAX_PATH = ;

	GetAppPath (pFileName);

	StringCchCat (pFileName, MAXPATH, T ("NewIOCPFile.txt"));

	HANDLE ahWThreadMAXWRITETHREAD = ;

	DWORD dwWrited = 0;

	// 建立檔案

	HANDLE hTxtFile = CreateFile (pFileName, GENERIC_WRITE, 0, NULL,

		CREATEALWAYS, FILEATTRIBUTENORMAL | FILEFLAG_OVERLAPPED, NULL);

	if (INVALIDHANDLEVALUE == hTxtFile) {tprintf (T ("CreateFile (% s) 失敗，錯誤碼：% u\n"), GetLastError );

		tsystem (T ("PAUSE"));

		return 0;

	}

	// 初始化執行緒池回撥環境

	TPCALLBACKENVIRON poolEnv = ;

	InitializeThreadpoolEnvironment (&poolEnv);

	// 建立 IOCP 執行緒池

	gpThreadpoolIo = CreateThreadpoolIo (hTxtFile, (PTPWIN32IOCALLBACK) IOCPCallback, hTxtFile, &poolEnv);

	// 啟動 IOCP 執行緒池

	StartThreadpoolIo (g_pThreadpoolIo);

	// 寫入 UNICODE 檔案的字首碼，以便正確開啟

	PERIODATA* pIo = (PPERIODATA) QMLXCALLOC (sizeof (PERIO_DATA));

	QMLX_ASSERT (pIo != NULL);

	pIo->mdwOp = OPWRITE;

	pIo->m_hFile = hTxtFile;

	pIo->mpData = QMLXCALLOC (sizeof (WORD));

	QMLXASSERT (pIo->mpData != NULL);

	((WORD) pIo->m_pData) = MAKEWORD (0xFF, 0xFE);

	pIo->m_nLen = sizeof (WORD);

	// 偏移檔案指標

	pIo->mol.Offset = gliFilePointer.LowPart;

	pIo->mol.OffsetHigh = gliFilePointer.HighPart;

	gliFilePointer.QuadPart += pIo->mnLen;

	pIo->m_dwTimestamp = GetTickCount ; // 記錄時間戳

	WriteFile (hTxtFile, pIo->mpData, pIo->mnLen,

		&pIo->mdwWrite, (LPOVERLAPPED)&pIo->mol);

	// 等待 IOCP 執行緒池完成操作

	WaitForThreadpoolIoCallbacks (g_pThreadpoolIo, FALSE);

	// 啟動寫入執行緒進行日誌寫入操作

	for (int i = 0; i m_dwOp)

	{

	case OP_WRITE:// 寫操作結束

	{// 寫入操作結束

		tprintf (T ("執行緒 0x% x 得到 IO 完成通知，完成操作 (% s), 緩衝 (0x%08x) 長度 (% ubytes), 寫入時間戳 (% u) 當前時間戳 (% u) 時差 (% u)\n"),

			GetCurrentThreadId , OPWRITE == pIo->mdwOp ? T ("Write") : T ("Read"),

			pIo->mpData, pIo->mnLen, pIo->mdwTimestamp, dwCurTimestamp, dwCurTimestamp - pIo->mdwTimestamp);

		QMLXSAFEFREE (pIo->mpData);

		QMLX_SAFEFREE (pIo);

	}

	break;

	case OP_READ: // 讀操作結束

		break;

	default:

		break;

	}

}

// 寫檔案的執行緒

define MAX_LOGLEN 256

DWORD WINAPI WriteThread (LPVOID lpParam)

{TCHAR pTxtContextMAX_LOGLEN = ;

	PPERIODATA pIo = NULL;

	size_t szLen = 0;

	LPTSTR pWriteText = NULL;

	StringCchPrintf (pTxtContext, MAXLOGLEN, T ("這是一條模擬的日誌記錄，由執行緒 0x% x 寫入 \r\n"),

		GetCurrentThreadId );

	StringCchLength (pTxtContext, MAX_LOGLEN, &szLen);

	szLen += 1;

	int i = 0;

	for (; i mdwOp = OPWRITE;

		pIo->m_hFile = (HANDLE) lpParam;

		pIo->m_pData = pWriteText;

		pIo->m_nLen = (szLen - 1) * sizeof (TCHAR);

		// 這裡使用原子操作同步檔案指標，寫入不會相互覆蓋

		// 這個地方體現了 lock-free 演算法的精髓，使用了基本的 CAS 操作控制檔案指標

		// 比傳統的使用關鍵程式碼段並等待的方法，這裡用的方法要輕巧的多，付出的代價也小

		((LONGLONG)&pIo->mol.Pointer) = InterlockedCompareExchange64 (&gliFilePointer.QuadPart,

			gliFilePointer.QuadPart + pIo->mnLen, g_liFilePointer.QuadPart);

		pIo->m_dwTimestamp = GetTickCount ; // 記錄時間戳

		StartThreadpoolIo (g_pThreadpoolIo);

		// 寫入

		WriteFile ((HANDLE) lpParam, pIo->mpData, pIo->mnLen,

			&pIo->mdwWrite, (LPOVERLAPPED)&pIo->mol);

		if (ERRORIOPENDING != GetLastError ) {CancelThreadpoolIo (g_pThreadpoolIo);

		}

	}

	return i;

}

.NET Framework 的執行緒池實現

名稱空間 System.Threading 中的類 ThreadPool 提供一個執行緒池，該執行緒池可用於執行任務、傳送工作項、處理非同步 I/O、代表其他執行緒等待以及處理計時器。