分享一个事务处理线程类

  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

Transaction.cpp

#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线程消息来控制,而可以用线程间隔一定时间来检查是否有事务需要处理,处理完事务后立即连续检查,没有新的事务则待会再检查的方式来控制了。

你可能感兴趣的:(C++,事务,线程)