gpt4 book ai didi

c++ - 每个线程一个类实例,C++11

转载 作者:行者123 更新时间:2023-11-30 01:14:58 24 4
gpt4 key购买 nike

我正在为多线程应用程序编写一个日志实用程序,我希望能够以类似 std::cout 的方式调用它:

线程 1:

Logger::log << "First message" << Logger::end;

线程 2:

Logger::log << "Second message" << Logger::end;

一旦 Logger::end 被传递到日志,消息应该被刷新到文件/屏幕/网络/无论日志去向。为了在不混淆消息的情况下处理对日志的并发写入,我的想法是为每个线程设置一个 Logger::log 实例,然后这些实例与一个专用于弹出新消息并将它们写入文件/屏幕等。

我猜想实现的一种方法是让某种多单例返回一个实例,具体取决于哪个线程 ID 正在调用它(也许从线程 ID 映射到存储在 std::map 中的日志)。有没有更好和/或更有效的方法?

是否有其他设计不需要每个线程一个日志实例,我忽略了这一点? std::cout 如何处理并发访问?

谢谢!

最佳答案

你可以使用 thread_local 单例:

class Logger {
public:
struct Sentinel{};

static thread_local Logger log;
static Sentinel end;

template<class T>
Logger& operator<<(T data) {
stream << data;
return *this;
}
//for endl and so on
Logger& operator<<(std::ostream& (*pf)(std::ostream&)) {
pf(stream);
return *this;
}

private:
Logger(){};
std::stringstream stream;
};

thread_local Logger Logger::log;
Logger::Sentinel Logger::end;

template<>
Logger& Logger::operator<<<Logger::Sentinel>(Logger::Sentinel data) {
stream << std::endl;
std::cout << stream.str();
stream.str("");
return *this;
}

另一种可能的语法:

class Logger_t {
public:
template<class T>
Logger_t& operator<<(T data) {
stream << data;
return *this;
}
//for endl and other stream manipulators
Logger_t& operator<<(std::ostream& (*pf)(std::ostream&)) {
pf(stream);
return *this;
}
void flush() {
std::cout << stream.str();
stream.str("");
}

private:
Logger_t(){};
std::stringstream stream;
friend Logger_t& Logger();
};

Logger_t& Logger() {
thread_local Logger_t logger;
return logger;
}

用法:

int main() {
Logger() << "test1 " << "test2" << std::endl;
Logger() << "test3" << std::endl;
Logger().flush();
Logger() << "test4" << std::endl; // <-- Not flushed
}

输出:

test1 test2
test3

编辑:
我重新审视了我的答案,虽然它展示了总体思路,但具体示例有一些注意事项:

  1. 同时 std::cout默认情况下是线程安全的,来自多个并行调用的单个字符 operator<<仍然允许交错。据我所知,这至少不会发生在 Ubuntu 上的 gcc 和 clang 上,但要真正便携,您可能必须保护对 std::cout 的任何访问。或您的日志系统使用的任何内容。
  2. 您必须确保没有人将对 Logger 实例的引用传递给另一个线程。我不知道为什么要这样做,但这对其他用户来说可能是一个令人惊讶的限制,因为“普通”单例并非如此。因此,将缓冲区变量设置为 stream 可能会更好。 thread_local而不是记录器。

关于c++ - 每个线程一个类实例,C++11,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29310211/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com