Why does libc++ allow recursive locking of std::mutex?

Viewed 196

std::mutex is nonrecursive, and violation of that is UB. So anything is possible in theory(including works as std::recursive_mutex)), but libc++ seems to work fine , this program outputs

bye

#include <iostream>
#include <mutex>

std::mutex m;
int main() {
    std::scoped_lock l1(m);
    std::scoped_lock l2(m);
    std::cout << "bye" << std::endl;
}

Is this intentional design decision in libc++ or just some accident(for example they could use same logic for mutex and recursive_mutex)?

libstdc++ hangs.

note: I am aware of that people should not rely on UB, so this is not about best practices, I am just curious about obscure implementation details.

2 Answers

It does not seem to be an intentional design decision. The libc++ implementation of std::mutex is just a wrapper around the platform's POSIX default mutex. Since that also is defined to have UB if locked recursively, they just inherited the fact that the platform's default POSIX mutex also happens to allow recursive locking.

I get the opposite results: libc++ hangs and libstdc++ doesn't

The reason is that if the file is not compiled with -pthread, threading support is disabled and std::mutex::lock/unlock become noops. Adding -pthread makes both of them deadlock as expected.

libc++ is built with threading support by default and doesn't require the -pthread flag, so it std::mutex::lock does actually acquire a lock, creating the deadlock.

Related