In a library where multiple threads may need to access std::cout, I made the following function so that access to std::cout is controlled (with a very simple example how to use it...):
// Mutexed access to std::out.
inline void HelperFunctions::controlStdCoutAccess(const StdCoutAccess mode)
{
static std::mutex m;
static std::unique_lock<std::mutex> lock(m, std::defer_lock);
// Check if we lock or unlock.
if (mode == StdCoutAccess::Lock)
lock.lock();
else
lock.unlock();
}
// Print to std::cout, but mutexed for thread safety.
inline void HelperFunctions::mutexedPrint(const std::string& string)
{
controlStdCoutAccess(StdCoutAccess::Lock);
std::cout << string;
controlStdCoutAccess(StdCoutAccess::Unlock);
}
In MSVC I get warnings: 'Failing to release lock', 'Failing to hold lock', 'Releasing unheld lock'. No warnings in gcc.
Is MVSC overlooking the possible usage of this construct, particularly mutex and lock being static? Or is the whole piece of code a bad idea and a better alternative exists? The warning just makes me wonder...
Making an RAII class like std::unique_lock
static defeats the purpose of it. If you need explicit calls to lock/unlock, you might as well call mutex.lock()
and unlock()
. The unlocking should happen automatically when the unique_lock
goes out of scope, e.g. after throwing an exception.
How about this instead:
inline std::unique_lock<std::mutex> lock_cout()
{
static std::mutex m;
return std::unique_lock<std::mutex>(m);
}
inline void HelperFunctions::mutexedPrint(const std::string& string)
{
auto lock = lock_cout();
std::cout << string;
}
If you have C++-20, you can use its synchronized IO routines instead:
#include <syncstream>
inline void HelperFunctions::mutexedPrint(const std::string& string)
{
std::osyncstream synced_out(std::cout);
synced_out << string;
}