On 21/08/20 13:12, Christian Schoenebeck wrote: > There is a golden rule with recursive locks: You always have to preserve a > clear hierarchy. Say you have the following recursive mutexes: > > RecursiveMutex mutex0; > RecursiveMutex mutex1; > RecursiveMutex mutex2; > ... > RecursiveMutex mutexN; > > where the suffix shall identify the hierarchy, i.e. h(mutex0) = 0, > h(mutex1) = 1, ... h(mutexN) = N. Then the golden rule is that in any call > stack the nested locks must always preserve the same transitive hierarchy, > e.g.:
That's also what you do with regular locks. But the difference is that with regular locks you can always do void bar(std::unique_lock<std::mutex> &mutex3_guard) { ... mutex3_guard.unlock(); synchronized(mutex2) { } mutex3_guard.lock(); ... } while with recursive locks you cannot, because you never know if mutex3_guard.unlock() is really going to unlock mutex3. So a simple reasoning on the invariants guaranteed by mutex3 has turned into interprocedural reasoning on all the callers of bar(), including callers of callers and so on. > For me, a non-recursive mutex makes sense for one use case: if the intention > is to lock the mutex on one thread while allowing to unlock it on another > thread. Then you want a semaphore, not a non-recursive mutex. Doing what you suggest with pthread_mutex or C++ std::mutex is undefined behavior. Paolo > For all other use cases I would (personally) prefer a recursive type, > as it guards a clear ownership relation and hence allows to guard and prevent > many mistakes. > > Best regards, > Christian Schoenebeck > >