线程池解决多线程难于管理的问题,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 write
GENERIC_WRITE, // open for writing
0, // do not share
NULL, // default security
CREATE_ALWAYS, // overwrite existing
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED , // FILE_FLAG_OVERLAPPED重叠模式
NULL);
//…
OVERLAPPED ov;
ZeroMemory(&ov,sizeof(OVERLAPPED));
if( FALSE == WriteFile(hFile, // open file handle
DataBuffer + dwBytesWritten, // start of data to write
dwBytesToWrite - 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);
}