JefferyZhou

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

在第一篇中主要由讨论日志的需求以及接口设计,这里阐述一下各个部分的实现过程。在设计过程中我们把整个系统分为三个部分:模块buffer, 线程buffer, 和内存日志系统接口。

首先我们需要明确的是我们的写入是正对线程来说,不同线程需要在不同的内存段进行写入操作,而线程内的写入操作是针对模块而来的。所以正在的写入操作在模块buffer里面,这里我们直接实现 一个前面设计的模块buffer:

 

//模块buffer
template <int nMaxBuffLen = MEMLOGSYS_MAX_BUFFE_LEN>
class IModuleBufferImp
{
public:
	typedef unsigned int size_t;

	static const unsigned int m_snMaxBuffLen = nMaxBuffLen;

	void WriteLog( const char* szBufferCache)									//写日志
	{
		WriteLog_Imp(GetTimeSting().c_str());
		WriteLog_Imp(szBufferCache);
		WriteLog_Imp("\n");
	}

	const char* GetMemLog()											//获取当前模块的日志信息
	{
		m_Buffer[m_snMaxBuffLen] = 0;
		return m_Buffer;
	}

	const char* GetModuleName()const
	{
		return m_szModuleName;
	}
	
	static IModuleBufferImp* CreateModuleBuffer(const char* pszModuleName)
	{
		IModuleBufferImp* pModuleBuffer = new IModuleBufferImp(pszModuleName);
		return pModuleBuffer;
	}

	static void DestroyModuleBuffer(IModuleBufferImp* pModuleBuffer)
	{
		SAFE_DELETE(pModuleBuffer);
	}

	static std::string GetTimeSting()
	{
		tm* pTimeStruct = Time::GetLOCALTime();

		char szTempBuffer[128] = {0};
		
		sprintf_s(szTempBuffer,"%.2d.%.2d.%.2d:%.2d:%.2d:%.10d  ",pTimeStruct->tm_mon,pTimeStruct->tm_mday,pTimeStruct->tm_hour,pTimeStruct->tm_min,pTimeStruct->tm_sec, GetTickCount());
		
		return std::string(szTempBuffer);
	}
protected:

	explicit IModuleBufferImp(const char* pszModuleName)
	{
		if (pszModuleName)
		{
			sprintf_s(m_szModuleName, MEMLOGSYS_MAX_MODULENAME_LEN-1, "%s", pszModuleName);
			m_szModuleName[MEMLOGSYS_MAX_MODULENAME_LEN-1] = 0;
		}else
		{
			memset(m_szModuleName, 0, MEMLOGSYS_MAX_MODULENAME_LEN);
			sprintf_s(m_szModuleName, MEMLOGSYS_MAX_MODULENAME_LEN-1, "%s", MEMLOGSYS_DEFAULT_MODULENAME);
		}

		m_WriteOffSet = 0;	
		memset(m_Buffer, 0, m_snMaxBuffLen);
	}

	~IModuleBufferImp()
	{
		;
	}

	bool WriteLog_Imp(const char* pszLog)
	{
		if (pszLog)
		{
			int len = strlen(pszLog);

			if (len >= m_snMaxBuffLen)	//超过最大值了
			{
				return false;
			}	

			if (m_WriteOffSet + len > m_snMaxBuffLen)
			{	
				memcpy(m_Buffer+m_WriteOffSet, pszLog, m_snMaxBuffLen - m_WriteOffSet);
				memcpy(m_Buffer,pszLog + (m_snMaxBuffLen - m_WriteOffSet), len-m_snMaxBuffLen + m_WriteOffSet);
			}else
			{
				memcpy(m_Buffer+m_WriteOffSet, pszLog, len);
			}

			m_WriteOffSet += len;

			if (m_WriteOffSet >= m_snMaxBuffLen)
			{
				m_WriteOffSet -= m_snMaxBuffLen;
			}

			return true;
		}
		return false;
	}
	

private:
	IModuleBufferImp(const IModuleBufferImp& rstIModuleBuffer){;};				//禁用
	IModuleBufferImp& operator = (const IModuleBufferImp& rstIModuleBuffer) {;};//禁用


	char m_szModuleName[MEMLOGSYS_MAX_MODULENAME_LEN];
	int	m_WriteOffSet;
	char m_Buffer[m_snMaxBuffLen + 1];
};

上面我们提供了一个简单的工厂函数来创建模块buffer, 并置拷贝构造函数和赋值构造函数为私有防止恶意拷贝。

在上面的实现过程中,有几个小细节需要注意:

  1。 我们是需要一个线程安全的写入类,所以在类的实现中不能出现任何多线程共享的可写字段。

  2。 线程Buffer 是一个循环日志,必须保证最后记录的完整性,以及记录的循环可读性,

            必须在写入记录的时候保证字符串结尾的0不屏蔽,数组中的有效内容。也就是在Write_Imp()里面用的是memcpy, 当然也可以使用 sprintf 系列,

            (读者也可以自行改为使用sprintf系列,如果使用sprintf系列需要仔细阅读相关文档, 比如 sprintf_s 保证最后给你加一个 0, 超过缓冲区会报错获设置错误标志位 : 这里有一个小tips,sprintf_s ,不仅在你的缓冲区里面输入内容,而且在后面加一个0,不仅加一个0,还会对0后面的有效缓冲区拿来做其他用途)

     3。 为了保证不破坏任何有效的完整记录,以及循环可读性,申请的缓冲区必须比可写缓冲区多一个字节用来存字符串结束符.

     4。 把构造函数定义为保护,提供一个简单工厂函数,这里把缓冲区定义为一个数组,而不是一个动态申请的空间,然后,这个时候工厂函数全部是new出的模块buff,所有你定义任何大小的缓冲区,只要不操作当前系统最大可申请内存数量就不会出现错误。

 

Sign Clown 2010.7.6 0:59 HDPY

大概实现就是上面了。后面另外两个部分,线程buff,系统管理接口的具体实现,会陆续展示。

[本文原创,转载请注明出处,在文章末尾提供原文链接http://www.cnblogs.com/JefferyZhou/,否则一旦发现,将按字节每人民币收费,绝不论价]

posted on 2010-07-06 01:02  JefferyZhou  阅读(2884)  评论(5编辑  收藏  举报