【发布时间】:2012-04-11 16:28:35
【问题描述】:
我正在尝试编写一个非常简单的线程安全记录器。理想情况下,我希望它像std::cout 一样工作,您可以重载<< 运算符,然后让所有内容神奇地显示在日志中。我在 Windows 机器上,所以这是我尝试过的方法:
// Threadsafe logger
class Logger
{
public:
Logger()
{
InitializeCriticalSection(&s);
}
~Logger()
{
DeleteCriticalSection(&s);
}
void Log(std::ostream const& os)
{
EnterCriticalSection(&s);
//std::cout << static_cast<std::stringstream const&>(os).str();
std::cout << os.rdbuf();
LeaveCriticalSection(&s);
}
private:
CRITICAL_SECTION s;
};
请注意,我对Log() 函数尝试了两种方法。我接受ostream 的原因是因为这就是stringstream 在调用<< 运算符后似乎产生的结果。当我运行此代码时,Log() 函数的两种变体都以相同的方式失败:
#include <iostream>
#include <sstream>
#include <Windows.h>
int main(int argc, char* argv[])
{
Logger logger;
//logger.Log(std::stringstream("Test"));
logger.Log(std::stringstream("Another ") << "test");
std::cin.get();
}
使用 Log 函数的两种变体输出第一行(“测试”)可以正常工作并正确显示。第二行输出一个错位的输出:
testher
这显然是test 覆盖Another。我对这些流的工作方式缺少什么?我尝试拨打flush 电话希望能解决问题,但它什么也没做。
我如何才能在线程安全的记录器上尝试与流一起正常工作?
【问题讨论】:
-
你试过 logger.Log((std::stringstream("Another")
-
我刚刚尝试过,它产生了相同的结果。感谢您的尝试!我认为应该是一样的,因为在调用
Log()函数之前,应该对所有函数参数进行全面评估。 -
我赞成 edransch 的回答,因为它描述了为什么你会得到这个结果,但 Jerry Coffin 的回答指出了一个不相关的严重问题。我可能会使用标准的 C++ 构造(例如,
<atomic>、<mutex>和<thread>)来解决它,因为它们已经拥有 C++ 所需的适当 RAII 语义。 -
或者只使用 fprintf,因为它已经是线程安全的:
fprintf(stdout,"%s\n",(std::stringstream() << "another" << " test").str().c_str()); -
同意——杰里的回答超越了我的整个方法,但 edransch 直接回答了问题的核心。我没有意识到 fprintf 是线程安全的——这是一个非常好的单行解决方案!
标签: c++ multithreading thread-safety iostream