線程池解決多線程難於管理的問題,Windows主要提供如下方式實現
- 非同步呼叫函數:伺服器用戶端模式下比較適用
- 定時回呼函數:避免使用多個定時器佔用主線程CPU處理時間
- 核心對象通知狀態回調:多個線程等待相同核心對象下適用
- 非同步IO請求完成時調用函數:非同步IO操作情形下適用
1)非同步呼叫函數實現
使用於伺服器端建立線程處理用戶端請求情景
MainThread->Wait for Client request->CreateThread handle request-> waitfor client request
使用:
伺服器端收到用戶端請求時調用
BOOL WINAPI QueueUserWorkItem(
__in LPTHREAD_START_ROUTINE Function,
__in_opt PVOID Context,
__in ULONG Flags
);
需要注意:執行過程中是無序的
DWORD WINAPI WorkProc(__in LPVOID lpParameter){DWORD dwThreadID=GetCurrentThreadId();int i =(int)lpParameter;printf("Thread:%d,time:%d,val:%d\n",dwThreadID,GetTickCount(),i);return 1;} void WorkItemDemo(){for(int i=0;i<100;i++){QueueUserWorkItem(WorkProc,(PVOID)i,WT_EXECUTEDEFAULT);}}
2)定時回呼函數
適用於需要啟動定時器且不影響主線程情形
VOID CALLBACK TimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired){if (lpParam == NULL){printf("TimerRoutine lpParam is NULL\n");}else{printf("thread:%d Timer routine called. Parameter is %d.\n",GetCurrentThreadId(),*(int*)lpParam);} } int _tmain(int argc, _TCHAR* argv[]){HANDLE hTimer[10];HANDLE hTimerQueue=NULL;int arg = 123; // Create the timer queue.hTimerQueue = CreateTimerQueue();if (NULL == hTimerQueue){printf("CreateTimerQueue failed (%d)\n", GetLastError());return 2;} int iArray[10] = {0,1,2,3,4,5,6,7,8,9}; for(int i=0;i<10;i++){// Set a timer to call the timer routine in 10 seconds.if (!CreateTimerQueueTimer( hTimer+i, hTimerQueue,(WAITORTIMERCALLBACK)TimerRoutine, iArray+i , 100+i*100, 100, 0)){printf("CreateTimerQueueTimer failed (%d)\n", GetLastError());return 3;}} // TODO: Do other useful work here//WaitForMultipleObjects(10,hTimer,true,INFINITE);Sleep(60*1000);printf("Call timer routine in 10 seconds...\n"); // Delete all timers in the timer queue.if (!DeleteTimerQueue(hTimerQueue))printf("DeleteTimerQueue failed (%d)\n", GetLastError()); return 0; }
3)核心對象通知狀態回調
適用於多線程等待某個相同核心對象通知,相同等待事件可有多個回調同時進入,在對象屬於通知狀態時可反覆調用多次….
VOID CALLBACK WaitOrTimerCallback0(__in PVOID lpParameter,__in BOOLEAN TimerOrWaitFired){//通知狀態自動調用static volatile LONG iCount=0;int i= (int)lpParameter;InterlockedIncrement(&iCount);printf("Thread:%d,val:%d,count:%d\n",GetCurrentThreadId(),i,iCount); } //...RegisterWaitForSingleObject(&hReg[0],hEvent,WaitOrTimerCallback0,0,100,WT_EXECUTEDEFAULT);//…SetEvent(hEvent);//…UnregisterWait(hReg[0]);
4)非同步IO請求完成時調用函數
需要注意使用重疊模式建立檔案和讀寫檔案,讀寫需要調用GetOverlappedResult擷取讀寫資料
DWORD g_DwWriten=0;VOID CALLBACK MyFileIOCompletionRoutine(__in DWORD dwErrorCode,__in DWORD dwNumberOfBytesTransfered,__in LPOVERLAPPED lpOverlapped){printf("thread:%d,trans:%d\n",GetCurrentThreadId(),dwNumberOfBytesTransfered);}//…hFile = CreateFile(pszFile, // name of the writeGENERIC_WRITE, // open for writing0, // do not shareNULL, // default securityCREATE_ALWAYS, // overwrite existingFILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED , // FILE_FLAG_OVERLAPPED重疊模式NULL);//…OVERLAPPED ov;ZeroMemory(&ov,sizeof(OVERLAPPED));if( FALSE == WriteFile(hFile, // open file handleDataBuffer + dwBytesWritten, // start of data to writedwBytesToWrite - dwBytesWritten, // number of bytes to write&dwBytesWritten, // number of bytes that were written&ov) // overlapped 重疊模式){if(GetLastError() != ERROR_IO_PENDING){printf("Could not write to file (error %d)\n", GetLastError());CloseHandle(hFile);return 0;}GetOverlappedResult(hFile,&ov,&dwBytesWritten,TRUE);}