实现一个单例模式需要:1>私有的构造函数。2>一个静态方法,返回这个唯一实例的引用。3>一个指针静态变量。4>选择一个解决多线程问题的方法。
1.把构造函数声明为私有,则只有Singleton类内的可以调用构造函数。
2.用静态方法来实例化这个对象,并返回这个对象。
3.利用一个静态变量来记录Singleton类的唯一实例。
4.解决多线程问题的方法如下
在陈硕的《Linux多线程服务端编程》上的使用pthread_once实现的单例模式
关于pthread_once的内容可以看:pthread_once
在static T& instance()中使用pthread_once()调用init,会保证init()只会调用一次。
template<typename T>
class Singleton : boost::noncopyable
{
public:
static T& instance(){
pthread_once(&once_, &Singleton::init);
return *value;
}
private:
Singleton();
~Singleton();
static void init()
{
value_ = new T();
}
private:
static pthread_once_t ponce_;
static T* value_;
};
template<typename T>
pthread_once_t Singleton<T>::ponce_ = PTHREAD_ONCE_INIT;
template<typename T>
T* Singleton<T>::value_ = NULL;
在C++中,std::call_once和std::once_flag代替了上面的pthread_once和pthread_once_t。
自己根据上面思路改编的一个C++单例模式:
Logger.h
#ifndef _LOGGER
#define _LOGGER
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <mutex>
#include <thread>
class Logger
{
public:
static const std::string kLogLevelDebug;
static const std::string kLogLevelInfo;
static const std::string kLogLevelError;
//
static Logger& instance();
//Logs a single message
void log(const std::string& inMessage,
const std::string& inLogLevel);
//Logs a vector of messages
void log(const std::vector<std::string>& inMessage,
const std::string& inLogLevel);
private:
// Static variable for the one-and-only instance
static Logger* pInstance;
// Constant for the filename
static const char* kLogFileName;
// Data member for the output stream
std::ofstream mOutputStream;
// Logs message.
void logHelper(const std::string& inMessage,
const std::string& inLogLevel);
static void init();
private:
Logger();
~Logger();
Logger(const Logger&);
Logger& operator=(const Logger&);
static std::mutex sMutex;
static std::once_flag mOnceFlag;
};
#endif
Logger.cpp
#include "Logger.h"
using namespace std;
const string Logger::kLogLevelDebug = "DEBUG";
const string Logger::kLogLevelInfo = "INFO";
const string Logger::kLogLevelError = "ERROR";
const char* Logger::kLogFileName = "log.out";
Logger* Logger::pInstance = NULL;
once_flag Logger::mOnceFlag;
mutex Logger::sMutex;
void Logger::init()
{
pInstance = new Logger();
}
Logger& Logger::instance()
{
call_once(Logger::mOnceFlag, &Logger::init);
//pthread_once(&ponce_, &Logger::init);
return *pInstance;
}
Logger::~Logger()
{
mOutputStream.close();
}
Logger::Logger()
{
mOutputStream.open(kLogFileName, ios_base::app);
if(!mOutputStream.good()){
cout<<"Unable to initialize the Logger!"<<endl;
}
}
void Logger::log(const string& inMessage, const string& inLogLevel)
{
lock_guard<mutex> lck(Logger::sMutex);
logHelper(inMessage, inLogLevel);
}
void Logger::log(const vector<string>& inMessages, const string& inLogLevel)
{
lock_guard<mutex> lck(Logger::sMutex);
for(size_t i=0; i<inMessages.size(); i++){
logHelper(inMessages[i], inLogLevel);
}
}
void Logger::logHelper(const string& inMessage, const string& inLogLevel)
{
mOutputStream<<inLogLevel<<":"<<inMessage<<endl;
}