C++ Mutex – Why Can’t I Check If a Mutex Is Locked?

c

C++14 seems to have omitted a mechanism for checking whether an std::mutex is locked or not. See this SO question:

https://stackoverflow.com/questions/21892934/how-to-assert-if-a-stdmutex-is-locked

There are several ways around this, e.g. by using;

std::mutex::try_lock()
std::unique_lock::owns_lock()

But neither of these are particularly satisfying solutions.

try_lock() is permitted to return a false negative and has undefined behaviour if the current thread has locked the mutex. It also has side-effects. owns_lock() requires the construction of a unique_lock on top of the original std::mutex.

Obviously I could roll my own, but I'd rather understand the motivations for the current interface.

The ability to check the status of a mutex (e.g. std::mutex::is_locked()) does not seem like an esoteric request to me, so I suspect the Standard Committee deliberately omitted this feature rather than it being an oversight.

Why?

Edit: Ok so maybe this use case isn't as common as I had expected, so I'll illustrate my particular scenario. I have a machine learning algorithm which is distributed on multiple threads. Each thread operates asynchronously, and returns to a master pool once it has completed an optimisation problem.

It then locks a master mutex. The thread must then pick a new parent from which to mutate an offspring, but may only pick from parents which do not currently have offspring that are being optimised by other threads. I therefore need to perform a search to find parents that are not currently locked by another thread. There is no risk of the status of the mutex changing during the search, as the master thread mutex is locked. Obviously there's other solutions (I'm currently using a boolean flag) but I thought the mutex offers a logical solution to this problem, as it exists for the purpose of inter-thread synchronization.

Best Answer

I can see at least two severe problems with the suggested operation.

The first one was already mentioned in a comment by @gnasher729:

You can't really reasonably check whether a mutex is locked, because one nanosecond after the check it can get unlocked or locked. So if you wrote if (mutex_is_locked ()) … then mutex_is_locked could return the correct result, but by the time the if is executed, it is wrong.

The only way to be sure that the “is currently locked” property of a mutex doesn't change is to, well, lock it yourself.

The second problem I see is that unless you lock a mutex, your thread doesn't synchronize with the thread that had previously locked the mutex. Therefore, it isn't even well-defined to speak about “before” and “after” and whether the mutex is locked or not is kind of asking whether Schrödiger's cat is currently alive without attempting to open the box.

If I understand correctly, then both problems would be moot in your particular case thanks to the master mutex being locked. But this doesn't seem like a particularly common case to me so I think that the committee did the right thing by not adding a function that might be somewhat useful in very special scenarios and cause damage in all others. (In the spirit of: “Make interfaces easy to use correctly and difficult to use incorrectly.”)

And if I may say, I think that the setup you currently have is not the most elegant and could be refactored to avoid the problem altogether. For example, instead of the master thread checking all potential parents for one that is not currently locked, why not maintain a queue of ready parents? If a thread wants to optimize another one, it pops the next one off the queue and as soon as it has new parents, it adds them to the queue. That way, you don't even need the master thread as a coordinator.