4 ms·
Isn't manually locking and unlocking (as seen in the examples) frowned upon anyway? In any development I do, and with every developer I've ever developed a pro
by SCHiM 10y ago
Isn't manually locking and unlocking (as seen in the examples) frowned upon anyway?
In any development I do, and with every developer I've ever developed a project internally, the use of std::lock_guard<> (which is a scope lock) was required when working with mutexes. This code looks like that classic "C with arrays" type of C++ code, that is prone to errors that have long been solved.
As a rule of thumb, when prototyping new multi threaded code and I have a class that needs to be thread safe, I add a scoped lock in every member function that is not const. Problem solved, your class is now thread safe, although not very performant...
- flamedoge 10y agothere's also std atomic.
- hellofunk 10y agoThat does not solve the issue of locks, just abstracts the mechanisms away (hence why std::atomic has member functions related to checking for locks). The OP is correct, these tools are generally frowned upon in favor of better strategies.
- flamedoge 10y agoIt offers finer grain control than simple mutexes. One can write lock-free data structure easily with it.
- hellofunk 10y agoThe very fact that atomics do lock means that you cannot properly write lock-free data structures with them. "Lock free" typically refers to code that can prevent blocking operations; atomics do not do that, though some people think of atomics as a simple lock-free method, it really isn't. Lock-free is about algorithm design that can prevent locking in the first place, and atomics still lock, even if they hide that from you. If you mentioned atomics as a lock-free tool in an interview, you'd likely be chided. Here is more information: http://preshing.com/20120612/an-introduction-to-lock-free-programming/ http://preshing.com/20120612/an-introduction-to-lock-free-pr... "when you attempt to satisfy the non-blocking condition of lock-free programming, a whole family of techniques fall out: atomic operations"
- aseipp 10y agoThese analysis passes also work just fine with scoped locks, using the SCOPE_CAPABILITY annotation (see the included mutex.h example). Scoped locks by themselves cannot statically rule out the same kinds of errors that this analysis can, in any case. Even if you only use scoped locks -- an obvious (but trivial) example is when you have a lock held but then attempt to take a lock again in some control path (perhaps through a recursive or deep call stack, or, in your case, calling another member function which also takes the lock unconditionally.) This is a trivial case for this analysis to detect but std::lock_guard<> alone will not save you. The annotations also serve as useful commentary and 'guiding tools' for refactoring as well, in my experience. If you annotate a function as yielding or taking a lock, and later change this -- the compiler will warn you that your annotation is out of sync with the implementation. In practice I find this quite useful to keep code clean, but it also obviously helps tell you if your change is correct, too. I normally just turn this analysis on in Clang, because IME it has very little negative effect and is very useful in practice.
- duneroadrunner 10y ago> when you have a lock held but then attempt to take a lock again in some control path (perhaps through a recursive or deep call stack, or, in your case, calling another member function The standard library provides std::recursive_mutex which supports being locked multiple times by the same thread. Unfortunately, it doesn't provide an std::recursive_shared_timed_mutex for the general case where you might want to support multiple simultaneous read operations. The SaferCPlusPlus library does implement such a mutex, and, like I mentioned in another comment, provides data types that automatically control access to shared objects. I think for most cases, it's the safest and easiest way to share objects asynchronously (in C++). (The data types are kind of analogous to Arc<> and Arc< Mutex<> > for those familiar with Rust.) Btw, the implementation is self-contained, so you can use the safe sharing data types without having to include the rest of the library. Or you can just copy the source code and make your own safe sharing data types.
- aseipp 10y agoThere are many people who would largely consider recursive mutexes a complete mistake, for the most part. I'm one of those people. :) But I admit I sort of willfully skipped over this point precisely because I dislike recursive mutexes. But they are there for this case, you are 100% right.