我有一个多线程应用程序,它大量使用 std::cout
进行无任何锁定的日志记录。在这种情况下,如何轻松添加锁定机制以使 std::cout
线程安全?
我不想搜索每次出现的 std::cout
并添加一行锁定代码。那太乏味了。
有更好的做法吗?
原文由 xmllmx 发布,翻译遵循 CC BY-SA 4.0 许可协议
我有一个多线程应用程序,它大量使用 std::cout
进行无任何锁定的日志记录。在这种情况下,如何轻松添加锁定机制以使 std::cout
线程安全?
我不想搜索每次出现的 std::cout
并添加一行锁定代码。那太乏味了。
有更好的做法吗?
原文由 xmllmx 发布,翻译遵循 CC BY-SA 4.0 许可协议
我遇到了和你类似的问题。您可以使用以下类。这仅支持输出到 std::cout
,但是如果您需要通用的,请告诉我。在下面的代码中, tsprint
创建了一个类 ThreadSafePrinter
的内联临时对象。 If you want, you can change tsprint
to cout
if you have used cout
instead of std::cout
, so you won’t have to替换 cout
的任何实例,但我一般不推荐这种做法。无论如何,从项目的开头开始对此类调试行使用特殊的输出符号要好得多。
我也喜欢这个解决方案: 1 。在我的解决方案中,所有线程都可以继续插入其相应的 thread_local
stringstream
静态对象,然后仅在需要刷新时才锁定互斥锁,这在析构函数中触发。这有望通过缩短互斥锁的持有时间来提高效率。也许我可以包含一个类似于 sync_endl
解决方案中提到的机制 1 。
class ThreadSafePrinter
{
static mutex m;
static thread_local stringstream ss;
public:
ThreadSafePrinter() = default;
~ThreadSafePrinter()
{
lock_guard lg(m);
std::cout << ss.str();
ss.clear();
}
template<typename T>
ThreadSafePrinter& operator << (const T& c)
{
ss << c;
return *this;
}
// this is the type of std::cout
typedef std::basic_ostream<char, std::char_traits<char> > CoutType;
// this is the function signature of std::endl
typedef CoutType& (*StandardEndLine)(CoutType&);
// define an operator<< to take in std::endl
ThreadSafePrinter& operator<<(StandardEndLine manip)
{
manip(ss);
return *this;
}
};
mutex ThreadSafePrinter::m;
thread_local stringstream ThreadSafePrinter::ss;
#define tsprint ThreadSafePrinter()
void main()
{
tsprint << "asd ";
tsprint << "dfg";
}
原文由 Eddie 发布,翻译遵循 CC BY-SA 4.0 许可协议
3 回答2k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.4k 阅读
1 回答1.6k 阅读✓ 已解决
注意:此答案是 C++20 之前的版本,因此它不使用
std::osyncstream
及其单独的缓冲,而是使用锁。我想您可以实现自己的类,该类包装
cout
并将互斥锁与它相关联。新类的operator <<
会做三件事:<<
这个不同的类会将锁和委托运算符
<<
到包装的流中。第二个类的析构函数最终会破坏锁并释放互斥锁。因此,您作为单个语句编写的任何输出,即作为
<<
调用的单个序列,只要您的所有输出都通过具有相同互斥锁的该对象,就会自动打印。我们将这两个类称为
synchronized_ostream
和locked_ostream
。如果sync_cout
是 --- 的一个实例,它包装了synchronized_ostream
std::cout
,那么序列将导致以下操作:
synchronized_ostream::operator<<
将获得锁synchronized_ostream::operator<<
将“Hello,”的打印委托给cout
operator<<(std::ostream&, const char*)
会打印“你好,”synchronized_ostream::operator<<
将构造一个locked_ostream
并将锁传递给它locked_ostream::operator<<
将打印name
--- 委托给cout
operator<<(std::ostream&, std::string)
将打印名称cout
的相同委托发生在感叹号和结束线操纵器上locked_ostream
临时被破坏,锁被释放