dimanche 5 mars 2017

Proper C++ way of implementing a lock_guard for custom library

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).

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?

Aucun commentaire:

Enregistrer un commentaire