O wise interwebs
We have an impasse between two colleagues that we could use your help resolving in the proper C++ way. Basically we have a set of utility classes, two of which are a Mutex and SpinLock class which both have the following abridged interface:
class Mutex {
public:
Mutex();
~Mutex();
void Lock();
void Unlock();
// ...
};
Obviously this is similar to, but differently-cased than the BasicLockable concept used by std::lock_guard, so we want something similar (assume that the Mutex class is immutable in this example; we cannot add the BasicLockable concept to it). Also not all of our compilers for supported platforms are fully c++11 featured, so we cannot just use vanilla c++11 support.
One school of thought is the following implementation of a generic guard class which can be inherited to provide a generic guard class and inherit from it to create a lock-guard class:
template<class T, void (T::*EnterFn)(), void (T::*ExitFn)()>
class Guard
{
public: // copy constructor deleting omitted for brevity
Guard( T *lock ) : m_lock(lock) { (m_lock->*EnterFn)(); }
~Guard(); { (m_lock->*ExitFn)(); }
private:
T *m_lock;
};
template<class T>
class LockGuard : public Guard<T, &T::Lock, &T::Unlock>
{
public:
LockGuard(const T* lock) : Guard<T, &T::Lock, &T::Unlock>(lock) {}
};
The other school of thought is to just implement a simple lockguard:
template<class T>
class LockGuard {
T* m_lockable;
public:
LockGuard(const T* lockable) : m_lockable(lockable) { lockable->Lock(); }
~LockGuard() { m_lockable->Unlock(); }
};
Which implementation would you choose and why? What is the most proper C++(03, 11, 14, 17) way of implementing it? Is there any inherent value to having a generic Guard class as described above?
I would not want to use method pointers.
Personally, I'd want to move towards the C++11 standard tools as much as possible. So I'd write an adapter.
template<class T>
struct lock_adapter {
T* t = nullptr;
void lock() { t->Lock(); }
void unlock() { t->Unlock(); }
lock_adapter( T& tin ):t(std::addressof(tin)) {}
// default some stuff if you like
};
template<class T>
struct adapted_unique_lock:
private lock_adapter<T>,
std::unique_lock< lock_adapter<T> >
{
template<class...Args>
adapted_unique_lock(T& t, Args&&...):
lock_adapter<T>(t),
std::unique_lock< lock_adapter<T> >( *this, std::forward<Args>(args)... )
{}
adapted_unique_lock(adapted_unique_lock&&)=delete; // sadly
friend void swap( adapted_unique_lock&, adapted_unique_lock& ) = delete; // ditto
};
now adapted_unique_lock has a restricted set of functionality from a std::unique_lock.
It cannot be moved, as the unique_lock holds a pointer to this inside its implementation and does not reseat it.
Note that the richness of the entire unique_lock constructor set is available.
Functions that return adapted unique locks must store their return values in something like auto&& references until end of scope, and you cannot return them through chains until C++17.
But any code using adapted_unique_lock can be swapped to use unique_lock once T has been changed to support .lock() and .unlock(). This moves your code base towards being more standard C++11, rather than bespoke.
I'll answer the question in your title since nobody else answered it.
According to the docs, lock_guard works on any type that "meets the BasicLockable requirements". BasicLockable only requires two methods, lock() and unlock().
In order to make lock_guard work with a custom library, you need to either add lock() and unlock() methods to the library's mutex class, or wrap it in another class that has lock() and unlock() methods.
You should use those: std::mutex, std::shared_lock, std::unique_lock,
std::timed_mutex, std::shared_mutex, std::recursive_mutex, std::shared_timed_mutex, std::recursive_timed_mutex, std::lock_guard if you actually have C++11 compiler. Otherwise it is more complex, and tag c++11 on question should be removed.
You can't implement spinlock or mutex with C\C++ means, you would need add assembler or intrinsic code - making it non-portable, unless you implement it for each platform - and with many x86-64 C++11 and later compilers you can't do inline assembler.
The main problem you would run into, if you use inherent locking logic is that objects behind mutexes or spinlocks are uncopyable. As soon as you copy it or if you copy defended variable, it stops being locked. Objects that are implementing mutex mechanics are uncopyable too.
Related
I have a class that I need to make thread-safe. I'm trying to do this by putting a unique lock at the top of every function in the class. The problem is that as soon as one function calls another function (in this class) the mutexes seem to lock each other, despite being in different functions. How can I stop this from happening?
An example is a class with get() and set() functions that both use a unique_lock at the start of each function. But in set() you want to call get() at some point, but without set()'s mutex locking get()'s mutex. However the mutex in get() should still work if called directly.
Making a class "thead safe" by adding a mutex to all operations is code smell. Doing so with recursive mutex is worse, because it implies a lack of control and understanding about what was locked and what operations lock.
While it often permits some limited multithreaded access, but leads very often to deadlocks, contention and performance hell down the lane.
Lock based concurrency does not safely compose except in limited cases. You can take two correct lock-based datastructures/algorithms, connect them, and end up with incorrect/unsafe code.
Consider leaving your type single threaded, implementing const methods that can be mutually called without synchronization, then using mixtures of immutable instances and externally synchronized ones.
template<class T>
struct mutex_guarded {
template<class F>
auto read( F&& f ) const {
return access( std::forward<F>(f), *this );
}
template<class F>
auto write( F&& f ) {
return access( std::forward<F>(f), *this );
}
mutex_guarded()=default;
template<class T0, class...Ts,
std::enable_if_t<!std::is_same<mutex_guarded, std::decay_t<T0>>, bool> =true
>
mutex_guarded(T0&&t0, Ts&&ts):
t(std::forward<T0>(t0),std::forward<Ts>(ts)...)
{}
private:
template<class F, class Self>
friend auto access(F&& f, Self& self ){
auto l = self.lock();
return std::forward<F>(f)( self.t );
}
mutable std::mutex m;
T t;
auto lock() const { return std::unique_lock<std::mutex>(m); }
};
and similar for shared mutex (it has two lock overloads). access can be made public and vararg woth a bit of work (to handle things like assignment).
Now calling your own methods is no problem. External use looks like:
std::mutex_guarded<std::ostream&> safe_cout(std::cout);
safe_cout.write([&](auto& cout){ cout<<"hello "<<"world\n"; });
you can also write async wrappers (that do tasks in a thread pool and return futures) and the like.
The std::recursive_mutex is what you want. It can be locked more than one time in one thread.
It could be more clear if you provided the code.
The problem arises from the fact that all the locks share the same mutex object. a recursive lock could to some extent solve the problem.
but bear in mind that getters do not necessarily have to be locked.
I confronted the same problem years ago, There were a couple of threads working together on a proxy object. The final solution was that I had to define more than one mutex. If it is possible, make use of Qt signals or boost signal each of which helps you come up with a better solution for passing data back and forth.
While using std::recursive_mutex will work, it might incur some overhead that can be avoided.
Instead, implement all logic in private methods that do not take the lock but assume the lock is held by the current thread of execution. Then provide the necessary public methods that take the lock and forward the call to the respective private methods. In the implementation of the private methods, you are free to call other private methods without worrying about locking the mutex multiple times.
struct Widget
{
void foo()
{
std::unique_lock<std::mutex> lock{ m };
foo_impl();
}
void bar()
{
std::unique_lock<std::mutex> lock{ m };
bar_impl();
}
private:
std::mutex m;
void foo_impl()
{
bar_impl(); // Call other private methods
}
void bar_impl()
{
/* ... */
}
};
Note that this is just an alternative approach to (potentially) tackle your problem.
I want to call methods of some class atomically from two threads.
I have non-thead-safe class, from third-party library, but need to use this class like that:
Main thread:
Foo foo;
foo.method1(); // while calling Foo::method1 object foo is locked for another threads
Second thread:
foo.method2(); // wait while somewere calling another methods from foo
How to use std::atomic at this situation? Or may be another solution (exclude use mutex and lock before and unlock after calling methods from foo)?
You cannot use std::atomic with user-defined types that are not trivially copyable, and the Standard only provides a limited set of specializations for certain fundamental types. Here you can find the list of all the standard specializations of std::atomic.
One approach you may want to consider is to write a general-purpose wrapper that lets you provide callable objects to be executed in a thread-safe manner on the wrapped object. Something along these lines was once presented by Herb Sutter in one of his talks:
template<typename T>
class synchronized
{
public:
template<typename... Args>
synchronized(Args&&... args) : _obj{std::forward<Args>(args)...} { }
template<typename F>
void thread_safe_invoke(F&& f)
{
std::lock_guard<std::mutex> lock{_m};
(std::forward<F>(f))(_obj);
}
// ...
private:
T _obj;
std::mutex _m;
};
This incurs some syntactic overhead in case you only want to call a single function in a thread-safe manner, but it also allows realizing transactions that must be performed atomically and may consist of more than one function call on the synchronized object.
This is how you could use it:
int main()
{
synchronized<std::string> s{"Hello"};
s.thread_safe_invoke([&] (auto& s)
{
std::cout << s.size() << " " << (s + s);
});
}
For a deeper analysis and implementation guidance, you may refer to this article on the subject as well as this one.
Share a std::mutex between the different threads. Where ever you use foo, wrap the calls with a std::unique_lock
in my program I have global data.
Every program module must have read and write access to the data. As of now, I do not use threading, but Qt's signals and slots and therefore - although I did not yet encounter crashes - I think I'll need synchronization somewhen.
Therefore, every module holds the data like this:
const std::vector<T>& data;
where T is a custom class. Therefore, every module can read the data. To keep it consistent, the vector itself is const to prohibit concurrent deletions or removals. Those are done using global functions (like addToData(T elem), removeFromData(int id)) which can be synchronized. Note that the vector itself is declared to be shared by reference, such that changes in one of the global functions above will result in consistent data in every program module.
==> That means that data can be read and added/removed from everywhere in a safe way.
The problem I encountered is modification of the data. The setters of T are aware of the race-conditions. Using data, I want to allow calls like data.at(3).setAttr("hello"), but for constant vectors, at() just returns constant references. Why and how can I make it work? I can cast the constness away, but that feels wrong.
I am also open for suggestions considering my architecture.
This scenario is exactly where you want to cast constness away. You have carefully designed your system to work correctly so don't feel badly about casting away const when you're completely ready for it's and it the right thing to do.
Synchronizing writes leaving reads non-synchronized may/will corrupt memory too.
Casting constancy away smells.
Working low overhead solution (though not well encapsulated) is below. Idea is well summarized in a #JonathanWakely's comment: "add a global function that takes a functor and applies it to the non-const vector"
header.h
struct no_synchronization {
struct mutex {}
struct guard {
guard(mutex&) {}
};
};
struct serialized {
typedef std::mutex mutex;
typedef std::lock_guard<mutex> guard;
};
template <class T, class S = no_synchronization>
class spaghetti {
typedef typename S::mutex mutex;
typedef typename S::guard guard;
static mutex mutex_;
static std::vector<T> vector_;
template <class F>
static void read_global_vec(F const& f) {
guard lock(mutex_);
std::vector<T> const& ref = vector_;
f(ref);
}
template <class F>
static void write_global_vec(F const& f) {
guard lock(mutex_);
f(vector_);
}
}
If the contents of the vector is changing infrequently then you can use copy-on-write with a shared_ptr to keep contention to the minimum.
Since you asked for suggestions
You can wrap vector, with a class that works mostly the same. This would also get rid of the global functions you mention, which is good. If you want the instance of your class to be const, use a mutable vector internally.
const_cast, but try to hide it somewhere in a function.
Store smart pointers. I hope I'm not wrong with this (it's been a while), but I think you can retrieve a non-const element through a const smart pointer.
To elaborate on (1) since I was asked to in the comment:
You need the functionality of vector, it's a pretty good match for your needs. But the interface of vector is clumsy for what you need. This is a situation which is often encountered, and a wrapper is the default solution. A wrapper is a new class, with an interface that matches your needs, but it's implementation is pretty much just delegating all the work to another class. The goal of using a wrapper is to make the wrapper object easier to use right and harder to use wrong. It might look somewhat like this (not tested, will not compile):
class AWrapperForDemonstration
{
public:
MyCustomClass& GetByIndex(int i) const // can throw
{
std::lock_guard<std::mutex> lock(_mutex);
return _storage[i];
}
size_t Size(int i) const
{
std::lock_guard<std::mutex> lock(_mutex);
return _storage.size();
}
void Add(MyCustomClass& addThis)
{
std::lock_guard<std::mutex> lock(_mutex);
_storage.push_back(addThis);
}
bool Remove(MyCustomClass& removeThis)
{
std::lock_guard<std::mutex> lock(_mutex);
auto it =_storage.find(removeThis);
if (it == _storage.end())
return false;
_storage.erase(it);
}
template <F> void ForEach(F const& f) const
{
std::lock_guard<std::mutex> lock(_mutex);
for (auto& i : _storage)
f(i);
}
private:
std::vector<MyCustomClass> _storage;
std::mutex _mutex;
}
I have the following problem: I have a class that needs to be protected from simultaneous access from different threads. The class has two methods: lock() and unlock() using (g_mutex_lock / g_mutex_unlock with a per-object GMutex). Now a locking method looks like this:
void Object::method()
{
lock();
// do stuff modifying the object
unlock();
}
Now lets assume that I have two mwthods of this type, method1() and method2() which I call one after another:
object.method1();
// but what if some other thread modifies object in between
object.method2();
I tried locking the object before this block und unlocking it again, but in this case
there is a deadlock even with a single thread because the GMutex doesn't know that it has already been locked by the same thread. A solution would be to modify the method to accept an additional bool to determine whether the object is already locked. But is there a more elegant concept? Or is this a shortcoming regarding the design concept in total?
The recursive mutex solution mentioned in other responses and comments will work just fine, but in my experience it leads to code that is harder to maintain, because once you switch to a recursive mutex it is all too easy to abuse it and lock all over the place.
Instead, I prefer to reorganize the code so that locking once is sufficient. In your example I would define the class as follows:
class Object {
public:
void method1() {
GMutexLock scopeLock(&lock);
method1_locked();
}
void method2() {
GMutexLock scopeLock(&lock);
method2_locked();
}
void method1_and_2() {
GMutexLock scopeLock(&lock);
method1_locked();
method2_locked();
}
private:
void method1_locked();
void method2_locked();
GMutex lock;
};
The "locked" versions of your methods are private, so they are only accessible from inside the class. The class takes responsibility in never calling these without the lock taken.
From the outside you have three choices of methods to call, depending on which of the methods you want to run.
Note that another improvement I've made is to not use explicit locking primitives but instead use the scope indirectly to lock and unlock. This is what GMutexLock does. An example implementation for this class is below:
class GMutexLock {
private:
GMutex* m;
GMutexLock(const GMutexLock &mlock); // not allowed
GMutexLock &operator=(const GMutexLock &); // not allowed
public:
GMutexLock(GMutex* mutex) {
m = mutex;
g_mutex_lock(m);
}
~GMutexLock() {
g_mutex_unlock(m);
}
};
Look up "recursive mutex" or "reentrant mutex" (versus the non-recursive mutex you're using now). These enable what you want. Some folks are not fans of recursive mutexes and feel they enable messy design.
Note that a recursive mutex cannot be locked on one thread and unlocked on another.
I personally would never use recursive mutexes (especially as such).
I would do some private functions that doesn't lock mutexes and lock around them in public functions' implementations.
I'm trying to implement a set of mutex and lock classes for an embedded system. I've never used tag dispatching before, and I'm not sure if I'm doing it right. The description included in the boost documentation simply has this:
struct input_iterator_tag { };
and uses it to pick a specialized template function. I don't have a template, I just want to pick a specific constructor based on the presence of a tag:
// in mutex.h:
struct TryLock { };
// defined nowhere, i.e. there's no cpp file for this:
extern TryLock try_lock;
template<typename MutexType>
class ScopedLock
{
public:
ScopedLock(MutexType& mtx) : m_mtx(mtx), m_acquired(true)
{
m_mtx.lock();
}
ScopedLock(MutexType& mtx, TryLock) : m_mtx(mtx)
{
m_acquired = m_mtx.tryLock();
}
...
}
and somewhere in my code I have a mutex which I want to lock:
Mutex mtx;
ScopedLock<Mutex> lock(mtx, try_lock);
This compiles fine and works. I'm just curious if I can get rid of the extern TryLock try_lock;, as I have the impression that it's somewhat superfluous.
You won't need the extern declaration for try_lock, if you replace its usage in the lock constructor call with a temporary:
Mutex mtx;
ScopedLock<Mutex> lock(mtx, TryLock());
Otherwise the compiler will pass a copy of try_lock to your constructor, at which point it will want to link against it.
When the standard library needs to do this, it uses constexpr:
struct piecewise_construct_t { };
constexpr piecewise_construct_t piecewise_construct = piecewise_construct_t();