【发布时间】:2014-01-07 18:03:27
【问题描述】:
我有一个 C++ 多线程程序。我在尝试通过多个线程和程序崩溃在日志中打印某些内容时遇到的问题。具体问题是我有 cout
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 正在刷新缓冲区,而另一个线程正在尝试放置换行符并遇到溢出。
可能的解决方案(但有问题)可能是: (1) 有一个可用于所有日志输出的独立线程安全记录器类,因此我们可以在所有地方使用 logger::cout 代替 std::cout ——这很乏味,因为日志记录分散在各处。此外,为了使这个线程安全,互斥锁和解锁需要在每次尝试调用插入运算符
还有其他更好的选择或想法来摆脱并发线程从 endl 操纵器引起的 SIGSEGV?
我可以在调用 endl 时以某种方式预先进行同步/互斥吗?
【问题讨论】:
-
问题是关于
cout还是endl?还是一般的流? -
std::cout 是所有线程共享的资源。因此,您应该使用锁或互斥锁小心地保护它。
-
您可以实现一个并发消息队列,线程将消息排入队列。请参阅有关该主题的Herb Sutter presentation(我为博客完成了实现它的练习,它似乎在 gcc 4.7 和 4.8 以及最新版本的 clang 上运行良好。)
-
endl,更准确地说。我猜 std::cout 应该是线程安全的。为每个日志输出使用互斥锁是乏味的,而且还会影响性能。
-
@DebasishJana 我闻到过早的优化。如果使用互斥锁太多,请考虑根本不记录,因为格式化用于记录的字符串可能比使用互斥锁要昂贵得多(它的额外好处是您的代码实际上可以正常工作)
标签: c++ multithreading