gpt4 book ai didi

c++ - 如何使 C++ endl 操纵器线程安全?

转载 作者:搜寻专家 更新时间:2023-10-30 23:58:23 25 4
gpt4 key购买 nike

我有一个 C++ 多线程程序。我在尝试通过多个线程和程序崩溃在日志中打印某些内容时遇到的问题。具体问题是我有 cout << "some log message"<< endl;当我看到转储核心的 pstack 时,它表明 endl 导致了争用问题。在一个线程上,我有:

 ff308edc _IO_do_write (ff341f28, ff341f6f, 2, ff341f6f, fc532a00, ff141f74) + dc
ff3094d8 _IO_file_overflow (ff341f28, a, ff000000, 1c00, 0, fffc00) + 2a8
ff3101fc overflow__7filebufi (ff341f28, a, 0, 1ffee, 7f2082, ff1b4f18) + 8
ff314010 overflow__8stdiobufi (a, a, ff314000, 4, fc532a00, fbdfbd51) + 10
ff306dd4 __overflow (ff341f28, a, 4, ff1b5434, ff1b5784, 82c8c) + 20
ff30fdd0 _IO_putc (a, ff341f28, 7d5be4, ff314048, ff1b5784, 82c8c) + 34
ff313088 endl__FR7ostream (7d5be0, 20, fbdfbd4e, 1, 0, 76f) + c
ff32a3f8 __ls__7ostreamPFR7ostream_R7ostream (7d5be0, 3bfb74, 3bf800, 385cd8, 76f, 0) + 4

在另一个线程上,我有:

 --- called from signal handler with signal 11 (SIGSEGV) ---
ff312f20 flush__7ostream (7d5be0, a, 4, ff1b5434, ff1b5784, 82c8c) + 10
ff312f58 flush__FR7ostream (7d5be0, ff341f28, 7d5be4, ff314048, ff1b5784, 82c8c) + 4
ff313090 endl__FR7ostream (7d5be0, 20, fbffbd4e, 1, 0, 232a) + 14

std::cout 被缓冲,std::endl 强制刷新输出流。因此,似乎在一个线程上 endl 正在刷新缓冲区,而另一个线程正在尝试 putc 换行符并遇到溢出。

可能的解决方案(但有问题)可能是:(1) 有一个独立的线程安全记录器类,可用于所有日志输出,因此我们可以在所有地方使用 logger::cout 而不是使用 std::cout —— 这很乏味,因为日志记录分散在各处。此外,为了使该线程安全,互斥锁定和解锁需要在每次尝试调用插入运算符 << 或类似 endl 的操作符之前和之后进行。这是一个性能打击。(2) 我们可以不使用 endl,而是使用 '\n',这样就不会在每次插入新行时都强制刷新,而是在需要时通过底层 ostream 缓冲机制进行刷新。但是,这个线程安全吗?没有把握。(3) 切换到 C++11,因为 C++11 的 std::cout 应该是线程安全的。但这不可能立即实现。

还有其他更好的替代方法或想法来消除并发线程从 endl 操纵器引起的 SIGSEGV 吗?

我可以在调用 endl 时以某种方式进行同步/互斥吗?

最佳答案

不只是endl,整个输出流都是共享的。它必须是那样真的。这是一个单一的公共(public)资源。而且图书馆不知道您想要的序列化。您必须将其添加到您的代码中。

这就是关于如果不序列化输出会发生什么。不同的输出片段可能会相互混淆,即使您设法避免运行时错误也是如此。因此,您必须决定程序中输出的原子单元,并将它们序列化。

关于c++ - 如何使 C++ endl 操纵器线程安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20677137/

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