Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iostream thread safety, must cout and cerr be locked separately?

I understand that to avoid output intermixing access to cout and cerr by multiple threads must be synchronized. In a program that uses both cout and cerr, is it sufficient to lock them separately? or is it still unsafe to write to cout and cerr simultaneously?

Edit clarification: I understand that cout and cerr are "Thread Safe" in C++11. My question is whether or not a write to cout and a write to cerr by different threads simultaneously can interfere with each other (resulting in interleaved input and such) in the way that two writes to cout can.

like image 493
zaphoyd Avatar asked Feb 01 '13 00:02

zaphoyd


People also ask

Is CERR thread-safe?

Insertion to and extraction from global stream objects ( std::cout, std::cin, std::cerr , and std::clog ) is thread-safe.

Is C++ cout thread-safe?

std::cout is thread-safe: The C++11 standard guarantees that you must not protect std::cout. Each character is written atomically. More output statements like those in the example may interleave. This interleaving is only a visual issue; the program is well-defined.

How do you ensure thread safety in C++?

It's safe to read and write to one instance of a type even if another thread is reading or writing to a different instance of the same type. For example, given objects A and B of the same type, it's safe when A is being written in thread 1 and B is being read in thread 2.

Is std :: Ofstream thread-safe?

So writing to any other std::ofstream is generally NOT thread safe. In particular, the document even further warns, that reading from a stream buffer is actually considered an [unsafe] write, as the buffer position is updated.


1 Answers

If you execute this function:

void f() {
    std::cout << "Hello, " << "world!\n";
}

from multiple threads you'll get a more-or-less random interleaving of the two strings, "Hello, " and "world\n". That's because there are two function calls, just as if you had written the code like this:

void f() {
    std::cout << "Hello, ";
    std::cout << "world!\n";
}

To prevent that interleaving, you have to add a lock:

std::mutex mtx;
void f() {
    std::lock_guard<std::mutex> lock(mtx);
    std::cout << "Hello, " << "world!\n";
}

That is, the problem of interleaving has nothing to do with cout. It's about the code that uses it: there are two separate function calls inserting text, so unless you prevent multiple threads from executing the same code at the same time, there's a potential for a thread switch between the function calls, which is what gives you the interleaving.

Note that a mutex does not prevent thread switches. In the preceding code snippet, it prevents executing the contents of f() simultaneously from two threads; one of the threads has to wait until the other finishes.

If you're also writing to cerr, you have the same issue, and you'll get interleaved output unless you ensure that you never have two threads making these inserter function calls at the same time, and that means that both functions must use the same mutex:

std::mutex mtx;
void f() {
    std::lock_guard<std::mutex> lock(mtx);
    std::cout << "Hello, " << "world!\n";
}

void g() {
    std::lock_guard<std::mutex> lock(mtx);
    std::cerr << "Hello, " << "world!\n";
}
like image 133
Pete Becker Avatar answered Nov 02 '22 23:11

Pete Becker