Unlocking a std::mutex
that wasn't locked is UB. Why is this so? Why doesn't it just have no effect, as the mutex isn't locked yet, or was already unlocked, so what's the harm of calling unlock again?
CodePudding user response:
Unlocking std::mutex that wasn't locked is UB. Why is it so? Why isn't it just have no effect, as mutex isn't locked yet, or was already unlocked, so what's the harm of calling unlock again?
Because that would have a cost. That would require every implementation to contain the necessary internal checks to ensure this behavior.
If you want a mutex that has this kind of behavior, you can code one up. But then you will have to pay the costs of the extra checks to do this. But then the people who don't need this behavior won't pay those costs.
The costs would tend to be higher than you might think. Owning a mutex makes accessing everything protected by that mutex safe. If you don't own a mutex, it isn't safe to access things protected by that mutex. So on some implementations, that might require the equivalent of acquiring a mutex (so you can safely access the mutex's ownership data) before you could release the mutex. If the cost to acquire and release a mutex are comparable, this might double the cost of unlocking a mutex. Yuck.
CodePudding user response:
It's historical.
It's possible to implement a mutex from semaphores. In this implementation, Unlocking increments a count, locking tests that it's not zero, then decrements it. (If memory serves, you need another semaphore to lock the "testing" bit - but I'll ignore that for this question). The only valid values for the mutex are 0 (locked) or 1 (unlocked).
By locking an already locked mutex, or by unlocking an unlocked mutex, you can drive the value outside the 0-1 range, making the mutex no longer perform correctly.
It's U/B, because it's possible to make mutexes that don't suffer from this issue, but not every system will have access to that kind of solution, so if you want portable C code, you have to have a mental-model of a simple count that increments/decrements, and only lock mutexes which or not locked. Only unlock mutexes that are locked.