multiple threads writing to std::cout or std::cerr

前端 未结 4 1346
醉话见心
醉话见心 2020-12-14 20:52

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

#pr         


        
相关标签:
4条回答
  • 2020-12-14 20:58

    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*),

    0 讨论(0)
  • 2020-12-14 21:00

    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.

    0 讨论(0)
  • 2020-12-14 21:07

    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 讨论(0)
  • 2020-12-14 21:18

    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.

    0 讨论(0)
提交回复
热议问题