Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is unlocking an unlocked std::mutex UB?

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?

like image 830
Random Avatar asked Aug 31 '21 23:08

Random


People also ask

What happens if you unlock an unlocked mutex?

If a thread attempts to unlock a mutex that it has not locked or a mutex that is unlocked, an error is returned. If the mutex type is PTHREAD_MUTEX_RECURSIVE, the mutex maintains the concept of a lock count. When a thread successfully acquires a mutex for the first time, the lock count is set to one.

How do you unlock a mutex?

The mutex does not become unlocked until the owner has called pthread_mutex_unlock() for each successful lock request that it has outstanding on the mutex. An errorcheck mutex checks for deadlock conditions that occur when a thread relocks an already held mutex.

Can mutex be unlock by another thread?

The thread that locks the mutex owns it, and the owning thread should be the only thread to unlock the mutex. If the mutex is destroyed while still in use, critical sections and shared data are no longer protected. This rule is a specific instance of CON31-C.

Does Unique_lock automatically unlock?

The std::scoped_lock and std::unique_lock objects automate some aspects of locking, because they are capable of automatically unlocking.


2 Answers

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.

like image 102
David Schwartz Avatar answered Oct 14 '22 05:10

David Schwartz


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.

like image 44
Tiger4Hire Avatar answered Oct 14 '22 03:10

Tiger4Hire