分享一个事务处理线程类

  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 <windows.h>
#include <process.h>

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值