我不太确定我是否了解情况,但听起来你想要一个代理:
class LogSingleton
{
public:
LogSingleton& instance() { /* ... */ }
void lock(); // lock mutex
void unlock(); // unlock mutex
template <typename T>
friend LogSingleton& operator<<(LogSingleton& pLog, const T& pX)
{
// needs to be locked first
assert(is_locked());
/* output pX however */
return pLog;
}
};
class LogProxy
{
public:
LogProxy()
{
// manage lock in proxy
LogSingleton::instance().lock();
}
~LogProxy()
{
LogSingleton::instance().unlock();
}
};
// forward input into the proxy to the log, knowing it's locked
template <typename T>
LogProxy& operator<<(LogProxy& pProxy, const T& pX)
{
LogSingleton::instance() << pX;
return pProxy;
}
// now expose proxy
typedef LogProxy log;
你会这样做:
log() << "its locked now" << "and the temporary will die" << "here ->";
加锁在构造函数和析构函数中完成,最后调用析构函数。
正如托尼正确指出的那样,这会使锁定时间过长。只有“最终”输出到LogSingleton
. 想象一下:
log() << "this next function takes 5 minutes"
<< my_utterly_crappy_function() << "ouch";
什么都没有记录,但互斥锁被锁定了很长时间。更好的是缓冲输出然后一次性输出:
class LogProxy
{
public:
~LogProxy()
{
// manage lock in proxy
LogSingleton::instance().lock();
// no-throw, or wrap mutex use in a scoped-lock
LogSingleton::instance() << mBuffer.rdbuf();
LogSingleton::instance().unlock();
}
// buffer output
template <typename T>
friend LogProxy& operator<<(LogProxy& pProxy, const T& pX)
{
mBuffer << pX;
return pProxy;
}
private:
std::ostringstream mBuffer;
};
现在在缓冲区准备好输出之前不会获取锁。