多个线程写入std::cout或std::cerr
multiple threads writing to std::cout or std::cerr
我有OpenMP线程,它们通过cout和cerr写入控制台。这当然是不安全的,因为输出可以交错。我可以做一些类似的事情
#pragma omp critical(cerr)
{
cerr << "my variable: " << variable << endl;
}
如果能用线程安全版本取代cerr,那就更好了,类似于valgrind DRD手册中解释的方法(http://valgrind.org/docs/manual/drd-manual.html#drd-manual-effective use),它涉及从std::ostreambuf派生一个类。理想情况下,最后我会用我自己的线程化cerr替换cerr,例如:
tcerr << "my variable: " << variable << endl;
这样的类一遇到"endl"就可以打印到控制台。我不介意来自不同线程的行是否交错,但每一行都应该只来自一个线程。
我真的不明白C++中的所有流媒体是如何工作的,它太复杂了。有人有这样的类吗?或者可以向我展示如何为此创建这样的类?
正如其他人所指出的,在C++11中,std::cout
是线程安全的。
然而,如果你像一样使用它
std::cout << 1 << 2 << 3;
对于不同的线程,输出仍然可以交错,因为每个<<
都是一个新的函数调用,它可以在另一个线程上的任何函数调用之前。
为了避免在没有#pragma omp critical
的情况下交织,可以执行以下操作:
std::stringstream stream; // #include <sstream> for this
stream << 1 << 2 << 3;
std::cout << stream.str();
将123写入流的三个调用仅发生在一个线程中,该线程指向本地非共享对象,因此不受任何其他线程的影响。然后,只有一个对共享输出流std::cout
的调用,其中项目123的顺序已经固定,因此不会被打乱。
您可以使用类似于字符串生成器的方法。创建一个非模板类:
- 提供模板化的
operator<<
以插入到该对象中 - 内部构建为
std::ostringstream
- 销毁时转储内容
粗略方法:
class AtomicWriter {
std::ostringstream st;
public:
template <typename T>
AtomicWriter& operator<<(T const& t) {
st << t;
return *this;
}
~AtomicWriter() {
std::string s = st.str();
std::cerr << s;
//fprintf(stderr,"%s", s.c_str());
// write(2,s.c_str(),s.size());
}
};
用作:
AtomicWriter() << "my variable: " << variable << "n";
或者在更复杂的场景中:
{
AtomicWriter w;
w << "my variables:";
for (auto & v : vars) {
w << ' ' << v;
}
} // now it dumps
如果你想要操纵器,你需要添加更多的重载,你可以使用write
比fprintf
更好地用于析构函数中的原子写入,或者std::cerr
,你可以泛化,以便将目标传递给构造函数(std::ostream
/文件描述符/FILE*
),
我没有足够的声誉来发布评论,但我想发布我添加到AtomicWriter类中的内容,以支持std::endl,并允许使用std::cout之外的其他流。这是:
class AtomicWriter {
std::ostringstream st;
std::ostream &stream;
public:
AtomicWriter(std::ostream &s=std::cout):stream(s) { }
template <typename T>
AtomicWriter& operator<<(T const& t) {
st << t;
return *this;
}
AtomicWriter& operator<<( std::ostream&(*f)(std::ostream&) ) {
st << f;
return *this;
}
~AtomicWriter() { stream << st.str(); }
};
将以下代码放入头文件atomic_stream_macro.h
#ifndef atomic_stream_macro_h
#define atomic_stream_macro_h
#include <mutex>
/************************************************************************/
/************************************************************************/
extern std::mutex print_mutex;
#define PRINT_MSG(out,msg)
{
std::unique_lock<std::mutex> lock (print_mutex);
out << __FILE__ << "(" << __LINE__ << ")" << ": "
<< msg << std::endl;
}
/************************************************************************/
/************************************************************************/
#endif
现在,宏可以从文件中使用,如下所示。
#include <atomic_stream_macro.h>
#include <iostream>
int foo (void)
{
PRINT_MSG (std::cout, "Some " << "Text " << "Here ");
}
最后,在main.cxx中,声明互斥对象。
#include <mutex>
std::mutex print_mutex;
int main (void)
{
// launch threads from here
}
可以通过继承std::basic_streambuf
来实现,并重写正确的函数以使其线程安全。然后将此类用于流对象。
- std::cout.imbue()多重调用
- 如何在C++中用std::cout正确显示带十六进制的字符串文本
- 为什么在C的循环中使用printf的Rust代码不显示输出,而在C++的循环中显示std::cout
- 为什么我应该在异常处理中使用std::cerr而不是std::cout
- std::cout输出int时出现编译错误
- 为什么 std::cout 打印浮点数、双精度和长双精度到相同的小数精度?
- main() 中的 std::cout 在调试期间不会在调试控制台中打印任何内容
- std::cout 来自多个线程
- 在 c++ 中以十六进制格式打印无符号字符(BYTE).使用 std::cout
- Cuda 基本程序 (将值写入矩阵和 std:cout 不起作用) ;主功能不启动
- 是否可以为 std::cout 创建别名?
- std::cout 在打印变量与函数表达式时的行为不同
- 带有 std::cout 的多线程控制台文本动画
- 捕获/禁止发送到 std::cout 的 OpenCV 警告
- printf() 和 std::cout 在指针方面的区别
- 使用字符串流加速 std::cout 日志记录
- 是否可以在每次使用std::cout时执行一个函数
- 为什么'std::cout << !+2 '输出 0?
- 如何将自定义类传递给std::cout
- 对于输出,std::copy是否比std::cout快