4 ms·
> - Mutex From their "Devguide": Clients of Mutex must obey these rules: 1. Each time a thread acquires a Mutex it must later release it. 2. A thread may no
by duneroadrunner 9y ago
> - Mutex
From their "Devguide":
Clients of Mutex must obey these rules:
1. Each time a thread acquires a Mutex it must later release it.
2. A thread may not attempt to release a Mutex unless it holds it.
3. A thread may not attempt to acquire an exclusive lock on a Mutex it already holds.
For basic sharing of resources between threads, using "access requesters"[1] can be safer and more convenient as they automatically take care of these rules for you.
And if you need to use the mutex directly, the SaferCPlusPlus library provides a "recursive_shared_timed_mutex"[2] (the one missing from the standard library), which allows a thread to hold multiple ("read" and/or "write") locks at the same time (relieving the "self-deadlock" issue). The mutex isn't documented, but it functions just as its name suggests.
[1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus#asynchronously-shared-objects https://github.com/duneroadrunner/SaferCPlusPlus#asynchronou...
[2] https://github.com/duneroadrunner/SaferCPlusPlus/blob/master/mseasyncshared.h#L78 https://github.com/duneroadrunner/SaferCPlusPlus/blob/master...
- slrz 9y agoRecursive mutexes? SaferCPlusPlus is not seriously recommending to replace standard/sane mutexes with their disfigured recursive cousins? Yuck. I thought people agreed long ago that their only valid use-case was papering over broken/non-existing resource access schemes in applications of yore, so you could try to speed them up sprinkling magic multi-threading pixie dust.
- duneroadrunner 9y agoSaferCPlusPlus does not recommend relying directly on mutexes at all. For most straightforward cases, you can use the "access requesters" to safely manage asynchronous access automatically. Recursive mutexes are analogous to having multiple pointers (or iterators), some of which are "non-const", to an object in the same thread at the same time. Some suggest that this too is a bad idea. For example, the Rust language does not allow a "mutable" (i.e. "non-const") reference to an object to co-exist with any other reference to that object, even in the same thread. SaferCPlusPlus does not necessarily disagree with this position, but it also does not require adherence to it, like Rust does. So if SaferCPlusPlus is going to allow multiple pointers (or iterators) to a shared object in the same thread, then it's going to need to lock the mutex protecting the object multiple times from the same thread. Giving each pointer/iterator its own separate lock, as opposed to having one lock encompass the all the pointer/iterators, allows the locks to be managed automatically, which ensures against data races, and that resource locks will be released as soon as it is safe to do so. Again, there's rarely any reason you'd need to interact with the mutex directly. It's primarily there to support "access requester" functionality. Also, note that this is a recursive shared mutex, not just a recursive mutex, which means that, for example, it provides a kind of "upgrade mutex" functionality. So if a thread has a "read" lock, it can obtain a "write" lock (blocking if necessary), without having to give up its read lock. Then when it's done with the write lock, it can release it without fear of losing its read lock (or blocking).
- slrz 9y agoThanks for the clarification. The analogy to multiple references (with ≥1 of them allowing for mutation) is an interesting one, though I don't quite understand why having that would imply a need for locking the same mutex multiple times. Will read up on the "access requester" mechanism though.
- 7197ghr918hf 9y agoTo my eyes, this code is much less clear than code that uses absl mutexes. Also, to my understanding, reentrant mutexes are much slower than ordinary mutexes, and are never necessary. But, I have been using absl mutexes for more than ten years, so I'm a bit biased.
- duneroadrunner 9y agoYeah, I think it might be a familiarity bias. Anyway, the point of access requesters are that they are much safer than manually protecting resources with mutexes. That is, using access requesters eliminates the possibility of data races[1]. Which is important because data races can be particularly insidious bugs. Just like how smart pointers can improve safety by automatically managing object lifetimes, access requesters can improve safety by automatically managing object lifetimes and asynchronous access. [1] As long as you adhere to the rule that shared objects not have "unprotected" mutable or indirect (i.e. pointers/references) members.