您的位置:首页 > 编程语言 > C语言/C++

C++内存日志系统(二)

2010-07-06 01:02 183 查看
在第一篇中主要由讨论日志的需求以及接口设计,这里阐述一下各个部分的实现过程。在设计过程中我们把整个系统分为三个部分:模块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/,否则一旦发现,将按字节每人民币收费,绝不论价]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: