0

qDebug() and std::cout are considered not to be thread safe since their docs do not mention anything regarding thread safety.

Which are thread safe printing syntaxes in C++, and Qt?

Aquarius_Girl
  • 21,790
  • 65
  • 230
  • 411
  • 3
    What does "thread-safe" mean to you? Writing to `std::cout` concurrently does not cause a data race. – Kerrek SB Dec 21 '15 at 02:11
  • @KerrekSB see this: http://stackoverflow.com/questions/6374264/is-cout-synchronized-thread-safe – Aquarius_Girl Dec 21 '15 at 02:14
  • @KerrekSB and this too: http://stackoverflow.com/questions/34379427/irregular-print-statements-in-multiple-producer-consumer-program – Aquarius_Girl Dec 21 '15 at 02:15
  • Writing to `std::cout` won't cause your program to crash, but you may get bits of output from different threads interspersed. For shorter strings (up to the buffer size), it normally suffices to prepare a line in a `std::ostringstream` or other buffer - including the newline, and write that e.g. with `std::cout << my_stringstream.str();`: most implementations will output that without intermingled output other threads. – Tony Delroy Dec 21 '15 at 02:16
  • I think you are going to have to synchronize writes using a `std::mutex`. – Galik Dec 21 '15 at 02:23
  • 1
    @TheIndependentAquarius: From your link, for C++11 "Concurrent access to a synchronized standard iostream [..] by multiple threads shall not result in a data race". – Jarod42 Dec 21 '15 at 02:28
  • Are you looking for a way to serialize output? – IInspectable Dec 21 '15 at 02:48
  • @IInspectable I don't know the meaning of serialize here. I just want the print statements to be printed in their complete form and in order in which they are written. That doesn't happen with cout and qDebug. – Aquarius_Girl Dec 21 '15 at 07:56

2 Answers2

1

Use an output method that locks a mutex before writing. That way only one thread will write at a time.

#include <iostream>
#include <ostream>
#include <sstream>
#include <mutex>

class Logger {
public:
    // destructor is called when output is collected and
    // the temporary Logger() dies (after the ";").
    ~Logger() {
        Logger::mutex_.lock(); // make sure I am the only one writing
        std::cout << buffer_.str(); // write
        std::cout << std::flush; // push to output
        Logger::mutex_.unlock(); // I am done, now other threads can write
    }

    // funny construct you need to chain logs with "<<" like
    // in std::cout << "var = " << var;
    template <typename T>
    Logger &operator<<(T input) {
        buffer_ << input;
        return *this;
    }

private:
    // collect the output from chained << calls
    std::ostringstream buffer_;

    // mutex shared between all instances of Logger
    static std::mutex mutex_;
};

// define the static variable. This line must be in one .cpp file
std::mutex Logger::mutex_;

int main()
{
    Logger() << "Hello" << " " << "World\n";
    Logger() << 123 << "test\n";
    return 0;
}

http://cpp.sh/3pd5m

Simon Warta
  • 10,850
  • 5
  • 40
  • 78
1

Both are thread safe in the sense that they will not cause your program to crash. Also the output is safe in the sense that all characters sent to the stream will be printed to their intentional value, e.g.

Thread A sends: {a,b,c,d}

Thread B sends: {1,2,3,4}

A valid output can be {a,b,1,2,3,c,d,4} but you will never see a character not from that set e.g. {m}.

In order to serialize your output you should use mutual exclusion the least through some globally accessible mechanism.

e.g. a simple class may well do that

class printsafe{
private:
  typedef std::mutex t_lock;
  static t_lock l_print;
public:
  static void print(std::string const & s}
  {
     std::lock_guard<printsafe::t_lock> l;
     std::cout << s ; // or qDebug(s.c_str());
  }
};

Now your output will be either {abcd1234} or {1234abcd} given that

thread A sends: abcd

thread B sends: 1234

Community
  • 1
  • 1
g24l
  • 3,055
  • 15
  • 28