一个模板线程池
一个模板线程池,没有使用信号灯,互斥体等同步对象。
主要思路是初始化一个管理线程,管理线程通过消息协调任务链表和工作线程之间如何更好的工作,消息通信使用PostThreadMessage。
下面是模板线程池源代码
// 添加新任务
case TM_ADDTASK:
OnAddTask(wParam, lParam);
break;
// 分配任务给空闲的工作线程
case TM_DISPOSETASK:
OnTmDisposeTask(wParam, lParam);
break;
// 删除所有的未处理的任务
case TM_DELETETASK:
OnDeleteTask(wParam, lParam);
break;
// 设置工作线程的个数
case TM_SETTHREADNUM:
OnSetThreadNum(wParam, lParam);
break;
default:
break;
}
}
private:
/*======================================================================
函数名称: static BOOL PostTM(DWORD dwID, UINT uMsg, WPARAM wParam, LPARAM lParam)
函数参数: DWORD dwID
需要发送的线程ID
UINT uMsg
需要发送的消息类型
WPARAM wParam
LPARAM lParam
返回值: 该函数执行成功返回TRUE,否则FALSE
函数说明: 仅仅是对PostThreadMessage进行一次封装,
在本机测试第一次用PostThreadMessage发送的时候会失败
======================================================================*/
static BOOL PostTM(DWORD dwID, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
#define TRY_COUNT 100
UINT nCount = 0;
while (nCount++ <= TRY_COUNT)
{
if (PostThreadMessage(dwID, uMsg, wParam, lParam))
{
return TRUE;
}
#ifdef _DEBUG
static DWORD dwCount = 0;
TRACE(_T("/t TRY_COUNT:%d Error:%d/n"), dwCount++, GetLastError());
#endif
Sleep(200);
}
// 发送消息失败,麻烦大了!!!
ASSERT(FALSE);
return FALSE;
}
/*======================================================================
函数名称: void OnTmDisposeTask(WPARAM wParam, LPARAM lParam)
函数参数: WPARAM wParam
LPARAM lParam
返回值: 无
函数说明: 给工作线程分配任务
======================================================================*/
void OnTmDisposeTask(WPARAM wParam, LPARAM lParam)
{
T* pT = NULL;
DWORD dwThreadId = 0;
while ((m_TaskList.size() != 0)
&& (m_dwIdleTId.size() != 0))
{
// 从任务链表中取出任务
pT = m_TaskList.front();
ASSERT(pT != NULL);
// 从空闲工作线程链表中取出其ID
dwThreadId = m_dwIdleTId.front();
// 把任务发送给工作线程
VERIFY(PostTM(dwThreadId,
TM_DISPOSETASK, (WPARAM)pT, 0));
m_TaskList.pop_front();
m_dwIdleTId.pop_front();
}
}
/*======================================================================
函数名称: void OnDeleteTask(WPARAM wParam, LPARAM lParam)
函数参数: WPARAM wParam
LPARAM lParam
返回值: 无
函数说明: 删除所有的未处理的任务
======================================================================*/
void OnDeleteTask(WPARAM wParam, LPARAM lParam)
{
T* pT= NULL;
while (m_TaskList.size() > 0)
{
pT = m_TaskList.front();
ASSERT(pT != NULL);
delete pT;
m_TaskList.pop_front();
}
}
/*======================================================================
函数名称: void OnKickIdle(WPARAM wParam, LPARAM lParam)
函数参数: WPARAM wParam
LPARAM lParam
返回值: 无
函数说明: 工作线程告诉管理线程该线程是空闲的
======================================================================*/
void OnKickIdle(WPARAM wParam, LPARAM lParam)
{
// 把线程加入空闲线程队列
m_dwIdleTId.push_back((DWORD)lParam);
VERIFY(PostTM((DWORD)m_ManagerTID,
TM_DISPOSETASK, 0, 0));
}
/*======================================================================
函数名称: void OnAddTask(WPARAM wParam, LPARAM lParam)
函数参数: WPARAM wParam
LPARAM lParam
返回值: 无
函数说明: 添加任务到任务链表中
======================================================================*/
void OnAddTask(WPARAM wParam, LPARAM lParam)
{
// 添加任务到任务链表中
ASSERT(wParam != 0);
// 把任务加入任务队列
m_TaskList.push_back((T*)wParam);
VERIFY(PostTM((DWORD)m_ManagerTID,
TM_DISPOSETASK, 0, 0));
}
/*======================================================================
函数名称: void OnSetThreadNum(WPARAM wParam, LPARAM lParam)
函数参数: WPARAM wParam
LPARAM lParam
返回值: 无
函数说明: 设置工作线程的个数
======================================================================*/
void OnSetThreadNum(WPARAM wParam, LPARAM lParam)
{
DWORD dwThreadNum = (DWORD)wParam;
if (dwThreadNum > m_dwThreadId.size())
{
VERIFY(CreateOperator(dwThreadNum - m_dwThreadId.size()));
}
else if (dwThreadNum < m_dwThreadId.size())
{
DestryOperator(m_dwThreadId.size() - dwThreadNum);
}
}
private:
unsigned int m_ManagerTID; // 管理者线程ID
list<DWORD> m_dwThreadId; // 工作线程的线程ID
deque<T*> m_TaskList; // 任务链
deque<DWORD> m_dwIdleTId; // 空闲线程
};
下面介绍如何使用这个模板线程池
1.任务类和模板实例化线程池类的定义及其实现
实现代码很简单,下面是线程池任务处理过程
strMsg.Format(_T("/tIndex:%08d/t%02d:%02d:%02d.%03d/t/tTID:%08x/n"),
rTask.m_nIndex, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, GetCurrentThreadId());
// 在调试窗口输出处理的任务
OutputDebugString(strMsg);
// 模拟线程处理消耗时间
DWORD dwSleep = st.wMilliseconds > 500? st.wMilliseconds : 500;
Sleep(dwSleep);
}
2. 在对话框中实例化这个线程池类,并使用
a.添加头文件,本例中是
b.实例化这个线程池类,本例中是添加到类成员变量中
c.初始化线程池对象
注:默认是初始化10个工作线程,你也可以在有空闲线程的时候调用SetThreadNum设置工作线程个数.
d.添加任务到线程池对象中
在VC6.0中可能会有内存泄露(大小:工作线程个数*sizeof(任务类)),在VS2008SP1中测试没有内存泄露.
需要在各个VS版本测试,请修改模板线程池的析构函数的_MSC_VER宏为对应的VS版本即可.