最后一个步骤是实现LogItem的集合,使用list实现。做的很简单,需要注意的是写入流(console或文件)这里尚未使用策略模板参数,而是是使用了一个静态类LogOutputPolicy,并且实际上也不该在LogQueue里使用它,应该在LogManager里使用较好。这里有些懒惰了,主要LogManager参数过多。
先看LogOutputPolicy的代码:
#ifndef __LogOutputPolicy_H__
#define __LogOutputPolicy_H__
#include "stdafx.h"
#include "LogConfigMacro.h"
#include "loki/Threads.h"
using namespace std;
template<
int ModuleID, class ItemType,
bool ToConsole = WRITE_TO_CONSOLE, bool ToFile = WRITE_TO_FILE,
template <class, class> class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL,
class MutexPolicy = LOKI_DEFAULT_MUTEX
>
class LogOutputPolicy
{
public:
typedef LogOutputPolicy<ModuleID, ItemType, ToConsole, ToFile, ThreadingModel, MutexPolicy> MyLogOutputPolicy;
//typename typedef ThreadingModel<MyLogOutputPolicy, MutexPolicy>::Lock Lock;
private:
static fstream ofile;
public:
static void openLog(DWORD id)
{
//Lock gurad;
if(ToFile)
{
char name[64];
sprintf_s(name, 64, "../thread_id(%d).txt", id);
ofile.open(name, ios_base::app);
}
}
static void closeLog()
{
//Lock gurad;
if(ToFile)
ofile.close();
}
static void writeLog(ItemType& item, DWORD id)
{
//Lock gurad;
if(ToConsole)
cout << item;
if(ToFile)
ofile << item;
}
};
template<
int ModuleID, class ItemType,
bool ToConsole , bool ToFile,
template<class, class> class ThreadingModel,
class MutexPolicy
>
fstream LogOutputPolicy<ModuleID, ItemType, ToConsole, ToFile, ThreadingModel, MutexPolicy>::ofile;
#endif
你希望怎么更改输出格式,输出窗口都可在LogOutputPolicy里定义。LogOutputPolicy你当然也可以实现自己的策略扩展,例如多个console窗口的选择,只是一个示例。
LogQueue代码简单,std的2个list作为logitem的容器,有自己的字符缓冲区一个LogItem类型的buffer。这个buffer是可以在LogManager里实现的,那样的话加锁很麻烦,已经解释过logx宏非原子操作。这里迫不得已在LogQueue里实现它。虽然感觉有些破坏结构,但仍有一些方便。
#ifndef __LogQueue_H__
#define __LogQueue_H__
#include "loki/Threads.h"
#include "LogOutputPolicy.h"
using namespace std;//为示例方便,直接使用std名字空间
template<
int ModuleID,
class ItemType_,
size_t QueueSize_ = 128
>
class LogQueue : public LOKI_DEFAULT_THREADING< LogQueue<ModuleID, ItemType_, QueueSize_>, LOKI_DEFAULT_MUTEX >
{
public:
typedef ItemType_ ItemType;
typedef LogQueue<ModuleID, ItemType_, QueueSize_> QueueType;
private:
list<ItemType*> m_freeLogQueue;
list<ItemType*> m_usedLogQueue;
DWORD m_id;
ItemType m_buffer;
public:
LogQueue<ModuleID, ItemType_, QueueSize_>(DWORD id):m_id(id) { init(); }
~LogQueue<ModuleID, ItemType_, QueueSize_>() { releaseQueue(); }
void pushString(const char* str)
{
//Lock guard(this);
ItemType* item = getItem();
assert(item);
(*item) << str;
pushItem(item);
}
void pushItem(ItemType* item)
{
//Lock guard(this);
m_usedLogQueue.push_back(item);
}
ItemType* getItem()
{
//Lock guard(this);
while(m_freeLogQueue.empty())
resizeQueue(QueueSize_);
ItemType* item = m_freeLogQueue.front();
m_freeLogQueue.pop_front();
return item;
}
void dispatchBuffer()
{
if( m_buffer.empty() )
return;
ItemType* item = getItem();
assert(item);
*item = m_buffer;
m_buffer.reset();
pushItem(item);
}
template<class T>
QueueType& operator << (const T& t)
{
m_buffer << t;
return *this;
}
void pumpQueue()
{
//Lock guard(this);
LogOutputPolicy<ModuleID, ItemType>::openLog(m_id);
while( !m_usedLogQueue.empty() )
{
LogOutputPolicy<ModuleID, ItemType>::writeLog(*m_usedLogQueue.front(), m_id);
m_freeLogQueue.push_back(m_usedLogQueue.front());
m_usedLogQueue.pop_front();
}
LogOutputPolicy<ModuleID, ItemType>::closeLog();
}
private:
void init()
{
resizeQueue(QueueSize_);
}
void resizeQueue(size_t size)
{
//Lock guard(this);
for(size_t i = 0; i < size; i++)
{
ItemType* item = new ItemType();
m_freeLogQueue.push_back(item);
}
}
void releaseQueue()
{
//if ( !m_usedLogQueue.empty() )
// pumpQueue();
ItemType* item;
while ( !m_freeLogQueue.empty() )
{
item = m_freeLogQueue.front();
assert(item);
delete item;
m_freeLogQueue.pop_front();
}
}
};
#endif
LogQueue根据QueueSize_参数决定初始化的empty list大小,。并可动态增长。这里为方便使用2个list,一个作为空的logitem池,一个则存放已经被占用的logitem。这里容器实现方式自己应需要更改吧。
至此整个LogSystem完毕。待完善的地方还很多,抛砖引玉,各位读者如有建议又有时间,贴上吧。但做下来感觉基于策略的思维真的很有感觉,实现过程中能磨练不少c++的设计思维。这半年都花了很多时间在c++的语法和设计方面,希望能够有所收获。接下来该是多学习算法,数据结构的时候了,面试的时候吃了不少亏哈。