[英]multiple threads writing to std::cout or std::cerr
我有通过 cout 和 cerr 写入控制台的 OpenMP 线程。 这当然是不安全的,因为输出可以交错。 我可以做类似的事情
#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 descriptor / 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(); }
};
您可以通过继承std::basic_streambuf
来完成它,并覆盖正确的函数以使其成为线程安全的。 然后将此类用于流对象。
将以下代码放入头文件
atomic_stream_macro.h<\/code>
#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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.