17
votes

I have OpenMP threads that write to the console via cout and cerr. This of course is not safe, since output can be interleaved. I could do something like

#pragma omp critical(cerr)
{
   cerr << "my variable: " << variable << endl;
}

It would be nicer if could replace cerr with a thread-safe version, similar to the approach explained in the valgrind DRD manual (http://valgrind.org/docs/manual/drd-manual.html#drd-manual.effective-use) which involves deriving a class from std::ostreambuf. Ideally in the end I would just replace cerr with my own threaded cerr, e.g. simply:

tcerr << "my variable: " << variable << endl;

Such a class could print to the console as soon as it encounters an "endl". I do not mind if lines from different threads are interleaved, but each line should come only from one thread.

I do not really understand how all this streaming in C++ works, it is too complicated. Has anybody such a class or can show me how to create such a class for that purpose?

4
please do not suggest printf.. ;)Wolfgang
"This of course is not safe" - This is not true in C++11, unless you take intentional action to make it true.Andy Prowl
Your title says cout not cerr.Barmar
@Wolfgang: What is the problem with printf or write? Build the string in a stringstream, then use printf/write for an atomic write of the whole line...David Rodríguez - dribeas
@AndyProwl: Even in C++11 the code above involves multiple calls to operator<<, which means that the output of different threads can be mixed to produce: myvariable: myvariable: 345 (now go figure whether the values are 3 and 45 or 34 and 5 :))David Rodríguez - dribeas

4 Answers

40
votes

As others pointed out, in C++11, std::cout is thread-safe.

However if you use it like

std::cout << 1 << 2 << 3;

with different threads, the output can still be interleaved, since every << is a new function call which can be preceeded by any function call on another thread.

To avoid interleaving without a #pragma omp critical - which would lock everything - you can do the following:

std::stringstream stream; // #include <sstream> for this
stream << 1 << 2 << 3;
std::cout << stream.str();

The three calls writing 123 to the stream are happening in only one thread to a local, non-shared object, therefore aren't affected by any other threads. Then, there is only one call to the shared output stream std::cout, where the order of items 123 is already fixed, therefore won't get messed up.

14
votes

You can use an approach similar to a string builder. Create a non-template class that:

  • offers templated operator<< for insertion into this object
  • internally builds into a std::ostringstream
  • dumps the contents on destruction

Rough approach:

 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());
    }
 };

Use as:

AtomicWriter() << "my variable: " << variable << "\n";

Or in more complex scenarios:

{
   AtomicWriter w;
   w << "my variables:";
   for (auto & v : vars) {
      w << ' ' << v;
   }
}  // now it dumps

You will need to add more overloads if you want manipulators, you can use write better than fprintf for the atomic write in the destructor, or std::cerr, you can generalize so that the destination is passed to the constructor (std::ostream/file descriptor/FILE*),

5
votes

I don't have enough reputation to post a comment, but I wanted to post my addition to the AtomicWriter class to support std::endl and allow for other streams to be used besides std::cout. Here it is:

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(); }
};
0
votes

You could do it by inheriting std::basic_streambuf, and override the correct functions to make it threadsafe. Then use this class for your stream objects.