Windows下创建线程是很简单的,具体创建线程的代码可以用AfxBeginThread(),也可以用CreateThread(),也可以用_beginthreadex()。大家写的恐怕手都磨出老茧了。
但是,有时候我们经常会遇到一种情况,比如说每隔一会我就要做一些事情,而且必须在线程里做。这时候该怎么办呢?最简单的办法当然是,每次都创建一个线程就OK了。但是身为程序员,我们不能对自己的要求仅仅是程序能运行就行了。作为一种更节约资源的办法,在程序启动的时候创建线程,后面在需要做一些事情的时候,把这些事情作为事务提交给线程处理。
当然了,以现在计算机的运行能力来说,每次都创建一个线程也不是什么问题。对于普通用户来说,程序每秒创建10个线程和程序一共只创建一个线程,基本上根本就感觉不出差别。但是我们自己必须知道,创建一个线程这样的内核对象,其实开销还是比较大的。从另一方面来说,一共只创建一个线程,方便对线程进行状态检测、控制。如果程序是运行在服务器端的话,那就更应该这样做了,每次都创建一个线程绝对不是个好主意。
这里,我提供一个基本的事务处理线程类的模板。
Transaction.h
#ifndef _WINDOWS_THREAD_TRANSACTION_H_
#define _WINDOWS_THREAD_TRANSACTION_H_
#pragma once
class CRunnable
{
public:
virtual void Run(void)=0;
};
class CTransaction
{
public:
CTransaction(void);
~CTransaction(void);
void Init();
void Clear();
void Do(CRunnable & run);
protected:
void* m_hThread;
unsigned m_ThreadID;
static unsigned __stdcall ThreadFunc(void* pArguments);
};
#endif
#include "Transaction.h"
#include
#include
#define UM_THREAD_NOTIFY (WM_USER + 150)
CTransaction::CTransaction(void):m_hThread(NULL),m_ThreadID(0)
{
}
CTransaction::~CTransaction(void)
{
if (0 != m_ThreadID)
{
Clear();
}
if (NULL != m_hThread)
{
::CloseHandle(m_hThread);
}
}
void CTransaction::Init()
{
m_hThread = (void*)_beginthreadex( NULL, 0, &CTransaction::ThreadFunc, this, 0, &m_ThreadID);
}
void CTransaction::Clear()
{
::PostThreadMessage((DWORD)m_ThreadID, WM_QUIT,0,0);
::Sleep(50);
DWORD dwExitCode = 0;
::GetExitCodeThread(m_hThread, &dwExitCode);
if (STILL_ACTIVE == dwExitCode)
{
DWORD dw = ::WaitForSingleObject(m_hThread ,1000);
switch (dw)
{
case WAIT_TIMEOUT:
::TerminateThread(m_hThread, 1);
break;
default:
;
}
}
m_ThreadID = 0; // 线程ID置0做为退出标志
}
unsigned __stdcall CTransaction::ThreadFunc(void* pArguments)
{;
CTransaction *p = (CTransaction*)pArguments;
MSG msg;
ZeroMemory(&msg,sizeof(MSG));
::PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
CRunnable * pRun = NULL;
BOOL bRet;
while ((bRet = ::GetMessage( &msg, 0, WM_QUIT, UM_THREAD_NOTIFY)) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
continue;
}
if (UM_THREAD_NOTIFY == msg.message)
{
pRun = (CRunnable*)msg.wParam;
pRun->Run();
}
}
_endthreadex(0);
return 0;
}
void CTransaction::Do(CRunnable & run)
{
::PostThreadMessage((DWORD)m_ThreadID, UM_THREAD_NOTIFY, (WPARAM)&run, 0);
}
具体的使用说明。对于要处理的事务,继承自CRunnable类,实现它的Run()方法。声明一个处理线程的全局或模块对象,比如命名为m_tran。在程序或者程序界面的初始化函数中调用m_tran.Init();对于事务类,声明相应的事务对象,必须是模块级对象或全局对象,不能是局部对象。比如说命名为m_myTran。
在要执行的时候调用
m_tran.Do(m_myTran);
这样就可以了。这个模型的实现利用了windows的线程消息。因为只创建了一个线程,所以基本不需要考虑互斥之类的问题。当然如果另外还创建了其他的线程,处理的事务中有操作其他线程也有操作的数据,那就需要考虑了。
这个模型应付一般的应用场景是没问题的。但如果事务处理的数量非常大,连续请求,就不太合适了。因为windows线程消息的响应速度并不很快。这时候相对来说效率就不很高。这种情况下就不适合用windows线程消息来控制,而可以用线程间隔一定时间来检查是否有事务需要处理,处理完事务后立即连续检查,没有新的事务则待会再检查的方式来控制了。