I decide to design a Log class which is thread-safe singleton.But there are some problems very annoying.When i use Mutex to lock,the log go fine.But when i use the CRITICAL_SECTION,the log will go wrong.And there is a very incredible phenomenon,the number of lock and unlock isn't same.The code is a little mess,maybe you can copy to your compiler.Here is my code:
#include<iostream>
#include<memory>
#include<fstream>
#include<Windows.h>
#include<string>
using namespace std;
#define MUTEX
#ifdef CRITICALSECTION
#define Mutex CRITICAL_SECTION
#define LOCK EnterCriticalSection
#define UNLOCK LeaveCriticalSection
#endif
#ifdef MUTEX
#define Mutex HANDLE
#define LOCK WaitForSingleObject
#define UNLOCK ReleaseMutex
#endif
class Lock
{
private:
Mutex _mutex;
public:
static int c,d;//In order to test the number of lock and unlock is the same
Lock(Mutex mutex):_mutex(mutex){
#ifdef MUTEX
LOCK(_mutex,INFINITE);
#endif
c++;
#ifdef CRITICALSECTION
LOCK(&_mutex);
#endif
}
~Lock(){
#ifdef MUTEX
UNLOCK(_mutex);
#endif
d++;
#ifdef CRITICALSECTION
UNLOCK(&_mutex);
#endif
}
};
int Lock::c = 0;
int Lock::d = 0;
class Log
{
private:
static Mutex m_mutex;
static ofstream m_log;
static Log* instance;
Log& operator = (Log&);
Log(Log&);
Log(){
#ifdef CRITICALSECTION
InitializeCriticalSection(&m_mutex);
#endif
};
public:
static Log& getinstance()
{
Lock m_lock(m_mutex);
if(!m_log.is_open())
m_log.open("server.log",ios::app);
return *instance;
}
Log& operator << (string s)
{
Lock m_lock(m_mutex);
m_log<<s.c_str()<<endl;
return *this;
}
};
#ifdef CRITICALSECTION
Mutex Log::m_mutex;
#endif
#ifdef MUTEX
Mutex Log::m_mutex = CreateMutex(NULL,false,"LOG");
#endif
Log* Log::instance = new Log();
ofstream Log::m_log;
You may not want to keep the log file open. (possible loss of data on abnormal termination; though std::endl flushes the stream from C++, the os may still be caching the data).
Note: The Microsoft implementation of std::mutex and friends uses Win32 critical sections (performance).